2016-12-15 4 views
1

Скажем, у меня есть 2 массива экземпляров класса «Человек». У класса Person есть свойства «имя», «возраст», «id». «id» - уникальный идентификатор, поэтому его можно использовать для сравнения людей. Так, скажем, у меня есть два массива людей:Вычитание двух массивов объектов на основе свойств объектов

[ {Name: Bob,Age: 18,ID: 142353}, {Name: Rob, Age: 40,ID: 142350}, {Name: Andy, Age: 30,ID: 142359}, {Name: Andy, Age: 21,ID: 142340} ] 

[ {Name: Jack,Age: 18,ID: 142362}, {Name: James, Age: 40,ID: 142311}, {Name: Rob, Age: 40,ID: 142350}, {Name: Andy, Age: 21,ID: 142340} ] 

Я хочу, чтобы сравнить идентификаторы людей и получить те, которые отличаются в массиве 1 из что в массиве 2, поэтому результат должен выглядеть следующим образом:

[{Name: Bob,Age: 18,ID: 142353}, {Name: Andy, Age: 30,ID: 142359}] 

как я это делаю сейчас в Swift является:

let new = newPeople.filter({ p1 in 
         previousPeople.contains(where: { p2 in 
          p1.id != p2.id 
     }) 
    }) 

Но я не думаю, что это работает. Не могу понять, что не так с моей реализацией.

+0

Возможные дубликат [Объединить массивы с условием] (http://stackoverflow.com/questions/40263697/merge-arrays-with-condition) – JPetric

+3

'пусть новый = newPeople.filter ({p1 в! PreviousPeople .contains (где: {p2 in p1.id == p2.id})}) – courteouselk

+0

Пожалуйста, используйте синтаксис закрывающего закрытия, чтобы избежать '})' всюду – Alexander

ответ

2

Вы хотите, чтобы ваш класс Person соответствовал Equableable протоколу.

extension Person: Equatable { 
    static func ==(lhs: Person, rhs: Person) -> Bool { 
     return lhs.id == rhs.id 
    } 
} 

, то вы можете сделать простой фильтр из двух массивов:

let person1 = Person(name: "J", age: 20, id: UUID()) 
let person2 = Person(name: "K", age: 40, id: UUID()) 
let person3 = Person(name: "L", age: 30, id: UUID()) 
let person4 = Person(name: "M", age: 25, id: UUID()) 
let person5 = Person(name: "N", age: 39, id: UUID()) 

let personArray1 = [person1, person2, person3] 
let personArray2 = [person4, person2, person3] 

let filteredPersonArray = personArray1.filter { !personArray2.contains($0) } 
//filteredPersonArray.count == 1 which is person4 
+0

Ваш отступ был повсюду. Я отредактировал и исправил его для вас. – Alexander

+1

Отличный ответ, но я предлагаю вам использовать набор. – Alexander

+0

спасибо, Александр, я все еще получаю зависание от форматирования. Хорошее предложение с набором, я об этом не думал. – JustinM

0

Создать Set из идентификаторов вы не хотите, чтобы сохранить и фильтровать людей, проверяя contains против этого Set , Вы можете получить Array идентификаторов от Array людей, используя people.map{ $0.id }.

struct Person { 
    let name: String 
    let age: Int 
    let id: Int 
} 

let people1 = [ 
    Person(name: "Bob", age: 18, id: 142353), 
    Person(name: "Rob", age: 40, id: 142350), 
    Person(name: "Andy", age: 30, id: 142359), 
    Person(name: "Andy", age: 21, id: 142340) 
] 

let people2 = [ 
    Person(name: "Jack", age: 18, id: 142362), 
    Person(name: "James", age: 40, id: 142311), 
    Person(name: "Rob", age: 40, id: 142350), 
    Person(name: "Andy", age: 21, id: 142340) 
] 


let undesiredIDs = Set(people2.map{ $0.id }) 
print("Keeping all people that don't have one of these IDs: \(undesiredIDs)\r\n\r\n") 

let filteredPeople = people1.filter{ !undesiredIDs.contains($0.id) } 

print("Original list: \(people1).\r\n\r\n") 
print("Filtered: \(filteredPeople)")