2016-05-01 12 views
0

Ich habe eine Reihe von CLLocations. Mein Ziel ist es, die letzte Position im Array mit der gleichen Position wie die folgenden Positionen zu finden und dann alle folgenden Objekte zu entfernen.Aufzählen zum Ausfiltern von ähnlichen Objekten in einem Array

Beispiel:

[lat: 11.123, long: 11.123, 
lat: 12.345, long: 123.123, 
lat: 14.124, long: 14.124, 
lat: 16.1661, long: 16.1616, 
lat: 15.1515, long: 15.1515, 
lat: 15.1515, long: 15.1515, //Remove 
lat: 15.1515, long: 15.1515] //Remove 

Ich mag würde das Array mutieren sie gespeichert sind in, statt einen neuen zu schaffen. so weit

Mein Versuch:

var reversedLocations = Array(locations.reverse()) 
      for (index,location) in reversedLocations.enumerate() { 
       if index+1 <= reversedLocations.count-1 { 
        let distanceToNext = LocationInterface.sharedInterface.distanceBetweenLocations(first: location, last: locations[index+1]) 
        if distanceToNext < 10 { 
         reversedLocations.removeAtIndex(reversedLocations.indexOf(location)!) 
         toDate = reversedLocations.first!.timestamp 
        } 
       } 
      } 

Aber dieser Code ist verwirrend, und ich bin nicht sicher, es ist die beste Art und Weise, es zu tun. Die Funktion ist nur ein Chaos, wie ich das Array im Enumeration mutieren, so dass der Index nicht korrekt ist. Gibt es Arrays.reduce, .sort, .map oder ähnliche, die mir dabei helfen können?

+0

sind:

die anderen Antworten werden auch

Die Lösung der OP verwendet, um alle anderen Duplikate andere als die Letzten entfernen Bist du sicher, dass das ein Array ist? – Carpsen90

+0

Das Beispiel ist kein syntax-korrektes Array, nein. Ich tippte das in mir selbst. Die Standorte sind in einem Array. –

Antwort

2
var locations = [1, 2, 3, 4, 5, 5, 5, 1, 2, 3, 4, 3, 3, 3] 

while !locations.isEmpty && locations.dropLast().last == locations.last 
{ 
    locations.removeLast() 
} 

print(locations) 

Mit Map benötigen, Reduce oder Filter ist nicht notwendig, in der Tat wäre es nicht, sie in diese empfohlen werden, um zu verwenden Fall. weil Sie aufhören sollten, alle Elemente zu lesen, wenn Sie ein anderes Element als das letzte gefunden haben.

Und wie @Eendje sagte:

   while !locations.isEmpty && (LocationInterface.sharedInterface.distanceBetweenLocations(first: locations.dropLast().last!, last: locations.last!) > 15) 
+0

Schöne Verwendung von 'dropLast' hier. Ich mochte meine Antwort nicht, da es zu viele Schritte erfordert, es sieht viel besser aus. – Eendje

+0

Schöne Umsetzung. Ich werde versuchen, dies zu ändern, um einige Ungenauigkeiten zu akzeptieren, und akzeptiere deine Lösung, wenn es für mich funktioniert. –

1

Vor allem, wenn Sie eine Reihe von CLLocation haben, dann wird es wie folgt

let locations: [CLLocation] = [ 
    CLLocation(latitude: 11.123, longitude: 11.123), 
    CLLocation(latitude: 12.345, longitude: 123.123), 
    CLLocation(latitude: 14.124, longitude: 14.124), 
    CLLocation(latitude: 16.1661, longitude: 16.1616), 
    CLLocation(latitude: 15.1515, longitude: 15.1515), 
    CLLocation(latitude: 15.1515, longitude: 15.1515), 
    CLLocation(latitude: 15.1515, longitude: 15.1515)] 

aussehen wahrscheinlich Jetzt können wir eine Set wie diese

var added = Set<CLLocation>() 

erstellen und schließlich das Array filtern

let filtered = locations.filter { (location) -> Bool in 
    let duplicate = added.contains { (location.coordinate.latitude, location.coordinate.longitude) == ($0.coordinate.latitude, $0.coordinate.longitude) } 
    guard !duplicate else { return false } 
    added.insert(location) 
    return true 
} 

Jetzt haben Sie Ihr Ergebnis innerhalb filtered.

1

Um dies zu tun, mit einer guten Zeit Komplexität, müssen Sie eine Reihe Datenstruktur Implementierung bestellt. Im Folgenden werde ich zeigen, wie dies mit einer reinen Swift-Lösung zu erreichen, die auf the OrderedSet library abhängt.

Wenn Sie nichts dagegen haben eine NSObject Unterklasse als Breitengrad & Länge Paartyp verwenden, können Sie dies tun, mit NSOrderedSet(array:…your location objects…).array wo …your location objects… auf Ihre NSObject Unterklasse bezieht, die die geografische Breite und Länge umschließt. Sie werden -hash und -isEqual: auf Ihre Location Klasse implementieren müssen. Das heißt, ist das Prinzip im Beispielcode unten sehr ähnlich: Sie haben eine Art benötigen, die Ihre Länge Paare Breite & enthält, die (außer Kraft setzen -hash in Ihrer NSObject Unterklasse) ist waschbar und gleichzusetzen (außer Kraft setzen -isEqual: in Ihrem NSObject).

import Darwin 
import SortedSet 

struct Location:Hashable { 
    let lat:Double 
    let long:Double 

    var hashValue: Int { 
     // This is a *terrible* hash function. 
     // You'll find instructions from elsewhere for more performant ones. 
     return Int(ceil(lat + long)) 
    } 
} 

func ==(lhs: Location, rhs: Location) -> Bool { 
    return lhs.lat == rhs.lat && lhs.long == rhs.long 
} 


let orderedLocations = OrderedSet<Location>(sequence: [Location(lat: 11.123, long: 11.123), 
                 Location(lat: 12.345, long: 123.123), 
                 Location(lat: 14.124, long: 14.124), 
                 Location(lat: 16.1661, long: 16.1616), 
                 Location(lat: 15.1515, long: 15.1515), 
                 Location(lat: 15.1515, long: 15.1515), 
                 Location(lat: 15.1515, long: 15.1515)]) 

for location in orderedLocations { 
    print(location) // prints out the locations in the original order, with duplicates removed. 
} 
1
let lastIndex = array.count - 1 

if array[lastIndex] == array[lastIndex - 1] { 
array.removeLast() 
} 

etwas wie das funktionieren würde. Möglicherweise müssen Sie es anpassen, um Ihre speziellen Anforderungen zu erfüllen.

* edit - diese anderen Lösungen suchen komplizierter, vielleicht falsch verstanden ich, was Sie

Verwandte Themen