2015-04-19 20 views
12

So finden Sie doppelte Elemente in Array? Ich habe eine Reihe von Telefonnummern, also sollte ich in den Telefonnummern anfangen, von der rechten Seite nach der linken Seite zu suchen und ähnliche 6 Ganzzahlen zu finden. Dann sollte ich sie ausdrucken.Suchen Sie doppelte Elemente in Array mit Swift

+0

warum würden Sie Ihre Funktion von cellForRow nennen ... der richtige Ansatz ist es, zuerst Duplikate zu finden und diese dann anzuzeigen ... – Volker

+0

mit dieser Funktion Ich sollte alle Kontaktinformationen im Array speichern und dann Suche in diesem Array durchführen ja? und danach werde ich ein neues Array mit doppelten Elementen erhalten und es wird einfach in der Zelle angezeigt werden? hab ich recht? – C0mrade

+0

Ihre Frage ist zu weit gefasst und mischt zwei verschiedene (nicht zusammenhängende) Probleme: 1) So finden Sie "doppelte Kontakte" im Adressbuch. 2) Wie man das Ergebnis in einer Tabellenansicht anzeigt. - Ich schlage vor, dass Sie Ihre Frage auf ein einzelnes Problem beschränken. Wenn das gelöst ist, können Sie bei Bedarf eine andere Frage stellen. –

Antwort

10

Um Duplikate zu finden, könnten Sie einen Querverweis nach Telefonnummer erstellen und diese dann nur auf Duplikate filtern. Betrachten wir zum Beispiel:

let contacts = [ 
    Contact(name: "Rob",  phone: "555-1111"), 
    Contact(name: "Richard", phone: "555-2222"), 
    Contact(name: "Rachel", phone: "555-1111"), 
    Contact(name: "Loren", phone: "555-2222"), 
    Contact(name: "Mary", phone: "555-3333"), 
    Contact(name: "Susie", phone: "555-2222") 
] 

In Swift 4 können Sie den Querverweis Wörterbuch mit bauen:

let crossReference = Dictionary(grouping: contacts, by: { $0.phone }) 

Oder

let crossReference = contacts.reduce(into: [String: [Contact]]()) { 
    $0[$1.phone, default: []].append($1) 
} 

Dann die Duplikate zu finden:

let duplicates = crossReference 
    .filter { $1.count > 1 }     // filter down to only those with multiple contacts 
    .sorted { $0.1.count > $1.1.count }  // if you want, sort in descending order by number of duplicates 

Verwenden Sie klar was auch immer mo del Typen sinnvoll für Sie, aber die oben verwendet den folgenden Contact Typen:

struct Contact { 
    let name: String 
    let phone: String 
} 

Es gibt viele, viele Möglichkeiten, dies zu implementieren, so würde ich auf den Details der Implementierung der oben nicht konzentrieren, sondern eher Fokus auf das Konzept: Erstellen Sie Querverweis Original-Array durch einen Schlüssel (z. B. Telefonnummer) und dann die Ergebnisse auf nur diese Schlüssel mit doppelten Werten filtern.


Es klingt wie Sie diese Struktur glätten wollen, dass die Duplikate, in einem einzigen Array von Kontakten (Ich bin mir nicht sicher, warum Sie das tun wollen würde reflektiert, wie Sie die Struktur zu identifizieren verlieren, die sind Duplikate voneinander), aber wenn Sie das tun wollen, können Sie es flatMap:

let flattenedDuplicates = crossReference 
    .filter { $1.count > 1 }     // filter down to only those with multiple contacts 
    .flatMap { $0.1 }      // flatten it down to just array of contacts that are duplicates of something else 

Für Swift 2 oder 3 Stellungen finden previous renditions of this answer.

+0

danke. also habe ich alles gemacht wie du sagtest aber ich habe nicht verstanden wieso es mir auf der konsole die duplikate aber 100 mal gibt? – C0mrade

+0

Ich frage mich, wie das ursprüngliche Array aussah. (Eine Ihrer anderen Fragen war das Hinzufügen von Zeilen zum Array innerhalb von 'cellForRowAtIndexPath'.) Überprüfen Sie das ursprüngliche Array (z. B. die Gesamtzahl" count ") und stellen Sie sicher, dass die Eingabe korrekt ist. – Rob

+0

Sorry nur eine Frage, ich habe meinen Fehler korrigiert und jetzt habe ich korrekte Anzahl von Zahlen und Namen, aber wie man das beheben: [(555-1111, [Name: Rob - Telefon 555-1111, Name: Rachel - Telefon 555- 1111])]. Wie ich getippt habe, sollte dies sein: Name: Rob - Telefon: 555-1111, Name Rachel - Telefon 555-1111 ... – C0mrade

4

Sie könnten es mit "Merge sort" implementieren, aber Sie müssen eine Änderung vornehmen, während der Zusammenführung sollten Sie die Duplikate ignorieren.

Der einfachste Weg, doppelte Elemente zu finden ist, wenn die Telefonnummer nur eine 6-stellige Nummer ist und Int hat, könnten Sie das Array von Telefonnummern sortieren und dann filtern, um Duplikate zu finden.

var phoneNumbers = [123456, 234567, 345678, 123456, 456789, 135790, 456789, 142638] 

func findDuplicates(sortedArray array: [Int]) -> [Int] 
{ 
    var duplicates: [Int] = [] 

    var prevItem: Int = 0 
    var addedItem: Int = 0 

    for item in array 
    { 
     if(prevItem == item && addedItem != item) 
     { 
      duplicates.append(item) 
      addedItem = item 
     } 

     prevItem = item 
    } 

    return duplicates 
} 

func sortPhoneNumbers(phoneNumbers: [Int]) -> [Int] 
{ 
    return phoneNumbers.sorted({ return $0<$1 }) 
} 

sortPhoneNumbers(phoneNumbers) 
findDuplicates(sortPhoneNumbers(phoneNumbers)) 

Außerdem könnten Sie die findDuplicates Methode auf unterschiedliche Weise implementieren:

Verwendung Set (Swift 1.2+):

func findDuplicates(array: [Int]) -> [Int] 
{ 
    var duplicates = Set<Int>() 
    var prevItem = 0  

    for item in array 
    { 
     if(prevItem == item) 
     { 
      duplicates.insert(item) 
     } 

     prevItem = item 
    } 

    return Array(duplicates) 
} 

Und so weiter.

+0

@Mazyod - Was? Überprüfen Sie den Code! – tikhop

+0

@Mazyod - von der Antwort: "Sie könnten das Array von Telefonnummern sortieren und dann FILTER, um Duplikate zu finden." – tikhop

+0

1. Die Funktion sollte das dann tun, da der Name nicht bedeutet, dass die Eingabe sortiert ist. 2. Wenn Sie genau hinsehen, setzen Sie 'prevItem' in jeder Iteration auf '0' zurück. – Mazyod

30

Gefühl ~ clever ~. eine Reihe von

s Int gegeben
let x = [1, 1, 2, 3, 4, 5, 5] 
let duplicates = Array(Set(x.filter({ (i: Int) in x.filter({ $0 == i }).count > 1}))) 
// [1, 5] 

Bitte beachten Sie, diese horrend effizient ist für alle Beteiligten, einschließlich der Compiler, und Sie.

Ich bin nur Angeberei.

+0

Brilliant !!!!!! – Pierce

+0

In der Tat schlau !! –

+0

Wissen Sie, welchem ​​Protokoll ich bei der Implementierung dieser Methode entsprechen muss? – MEnnabah

5

ein Array filtern auf Eigenschaften basiert, können Sie diese Methode verwenden:

extension Array { 

    func filterDuplicates(@noescape includeElement: (lhs:Element, rhs:Element) -> Bool) -> [Element]{ 
     var results = [Element]() 

     forEach { (element) in 
      let existingElements = results.filter { 
       return includeElement(lhs: element, rhs: $0) 
      } 
      if existingElements.count == 0 { 
       results.append(element) 
      } 
     } 

     return results 
    } 
} 

, die Sie als gefolgt, bezogen auf die Kontakte Beispiel Rob anrufen:

let filteredContacts = myContacts.filterDuplicates { $0.name == $1.name && $0.phone == $1.phone } 
1

Gleiche wie in @tikhop ‚s Antwort, aber als Array-Erweiterung (Swift 3):

extension Array where Element: Comparable & Hashable { 

    public var duplicates: [Element] { 

     let sortedElements = sorted { $0 < $1 } 
     var duplicatedElements = Set<Element>() 

     var previousElement: Element? 
     for element in sortedElements { 
     if previousElement == element { 
      duplicatedElements.insert(element) 
     } 
     previousElement = element 
     } 

     return Array(duplicatedElements) 
    } 

} 
1

Eine sehr einfache Antwort, die alle bewahrt Duplikate

let originalNums = [5, 3, 2, 3 , 7 , 5,3] 
var nums = Array(originalNums) 

let numSet = Set(nums) 

for num in numSet { 
    if let index = nums.index(of: num) { 
    nums.remove(at: index) 
    } 
} 

Ausgang

[3, 5, 3] 
0

Ich hatte auch ein ähnliches Problem und habe in der folgenden Art und Weise zu überwinden. (Xcode 8.3.2)

let a = [123456, 234567, 345678, 123456, 456789, 135790, 456789, 142638] 
var b = a // copy-on-write so that "a" won't be modified 

while let c = b.popLast() { 
    b.forEach() { 
    if $0 == c { 
     Swift.print("Duplication: \(c)") 
    } 
    } 
} 

// Duplication: 456789 
// Duplication: 123456 

Der Punkt ist, dass die Anzahl der Vergleiche. Es wäre kleiner als andere.

Angenommen, die Anzahl der Elemente im Array ist N. In jeder Schleife wird die Anzahl um eins verringert. Also ist die Gesamtzahl (N-1) + (N-2) + (N-3) + ... + 2 + 1 = N * (N-1)/2 Wenn N = 10, das dass einige Algorithmen werden 9 + 8 + ... = 45

Im Gegensatz dazu könnte N sein * N. Wenn N = 10, die 100

trotz alledem wird unter Berücksichtigung von die Kosten für die tief Kopie oder seicht-Kopie, ich bin einverstanden, dass @Patrick Perini brillante Art und Weise in einigen Situationen als dies besser wäre, auch die Zahl der, dass

EDIT N * N. wäre:

Alternative Art und Weise mit IteratorProtocol

let a = [123456, 234567, 345678, 123456, 456789, 135790, 456789, 142638] 
var i = a.makeIterator() 

while let c = i.next() { 
    var j = i 
    while let d = j.next() { 
    if c == d { 
     Swift.print("Duplication: \(c)") 
    } 
    } 
} 

// Duplication: 123456 
// Duplication: 456789 

, den komplexen aussieht, sondern verwendet die gleiche Idee wie zuvor. Dies hat keine unnötigen Speicherzuweisungen oder Kopien.

Mein Anliegen ist Effizienz, dh schnellere UI-Reaktion, längere Akkulaufzeit, kleinerer Speicherbedarf usw. Die Vermeidung unnötiger Speicherzuweisungen und/oder Speicherkopien, die von Swift automatisch im Hintergrund vorgenommen werden, wäre von entscheidender Bedeutung wettbewerbsfähige Produkte. (-;

1

Ich habe einen Weg gefunden, durch Verringerung verwenden, hier ist der Code (Swift 4):

let testNumbers = [1,1,2,3,4,5,2] 
let nondupicate = testNumbers.reduce(into: [Int]()) { 
    if !$0.contains($1) { 
     $0.append($1) 
    } else { 
     print("Found dupicate: \($1)") 
    } 
} 

Als Nebeneffekt, es gibt ein Array keine dupicated Elemente hat

.

Sie können es für das Zählen von doppelten Elementnummern, das Überprüfen von String-Arrays usw. einfach ändern.

0

Antoine's solution in Swift 3+ Syntax

extension Array { 

    func filterDuplicates(includeElement: @escaping (_ lhs: Element, _ rhs: Element) -> Bool) -> [Element] { 

     var results = [Element]() 

     forEach { (element) in 

      let existingElements = results.filter { 
       return includeElement(element, $0) 
      } 

      if existingElements.count == 0 { 
       results.append(element) 
      } 
     } 
     return results 
    } 
} 
Verwandte Themen