使用Swift在数组中查找重复元素

时间:2015-04-19 08:32:04

标签: arrays swift ios8 addressbook

如何在数组中查找重复元素?我有一系列电话号码所以在电话号码中我应该从右侧开始搜索到左侧并找到类似的6个整数。然后我应该打印出来。

14 个答案:

答案 0 :(得分:40)

感觉〜聪明〜。给定一组Int s

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]

请注意,这对所有参与者来说都非常有效,包括编译器和你。

我只是炫耀。

编辑: lol有人对此进行了贬低,这让我重申,以防万一:请不要在生产中或其他任何地方使用它。

答案 1 :(得分:22)

要查找重复项,您可以按电话号码构建交叉引用,然后将其过滤为仅重复。例如,考虑:

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")
]

在Swift 4中,您可以使用以下命令构建交叉引用字典:

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

或者

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

然后,找到重复项:

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

清楚地使用对您有意义的任何模型类型,但上面使用以下Contact类型:

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

有许多方法可以实现这一点,所以我不会专注于上面的实现细节,而是专注于这个概念:通过某个键(例如电话号码)构建交叉引用原始数组和然后将结果过滤到具有重复值的那些键。


听起来你想把这个反映重复的结构扁平化成一个单一的联系人阵列(我不知道你为什么要这样做,因为你失去了识别哪些是彼此重复),但如果你想这样做,你可以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

对于Swift 2或3版本,请参阅previous renditions of this answer

答案 2 :(得分:6)

要根据属性过滤数组,可以使用以下方法:

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
    }
}

根据Rob的联系人示例,您可以按照以下方式调用:

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

答案 3 :(得分:5)

您可以使用"Merge sort"实现它,但是您需要进行一次修改,在合并步骤中您应该忽略重复项。

查找重复元素的最简单方法是,如果电话号码只是一个6位数字且类型为Int,您可以对电话号码数组进行排序,然后对其进行过滤以查找重复项。

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))

此外,您可以通过不同方式实现findDuplicates方法:

使用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)
}

等等。

答案 4 :(得分:3)

基于Rob's answer,仅查找重复项的数组扩展名是:

extension Array where Element: Hashable {
    func duplicates() -> Array {
        let groups = Dictionary(grouping: self, by: {$0})
        let duplicateGroups = groups.filter {$1.count > 1}
        let duplicates = Array(duplicateGroups.keys)
        return duplicates
    }
}

答案 5 :(得分:2)

Swift 3 + 语法

中的

Antoine's solution

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
    }
}

答案 6 :(得分:1)

@tikhop 的答案相同,但作为数组扩展名(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)
   }

}

答案 7 :(得分:1)

我通过使用reduce找到了一种方法,这里是代码(Swift 4):

public class Object1 {
    private BigDecimal field1;
    private String field2;
    private String field3;
}
public class Object2 {
    private BigDecimal field1;
    private String field2;
}

List<Object1> list1 = new ArrayList<Object1>();
List<Object2> list2 = new ArrayList<Object2>();
List<Object1> listFilter = new ArrayList<Object1>();
for (Object object1 : list1) {
    for (Object object2 : list2) {
        if(object1.getField1().compareTo(object2.getField1())==0) {
            listFilter.add(object1);
            break;
        }
    }
}

作为副作用,它返回一个没有重复元素的数组。

您可以轻松修改它以计算重复的元素数,检查字符串数组等。

答案 8 :(得分:0)

一个非常简单的答案,可以保留所有重复项

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)
  }
}

输出

[3, 5, 3]

答案 9 :(得分:0)

我也有类似的问题,并以下列方式克服了。 (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

重点是比较的数量。它会比其他人小。

假设数组中的项数是N.在每个循环中,数字将减1。 所以,总数将是(N-1)+(N-2)+(N-3)+ ... + 2 + 1 = N *(N-1)/ 2 当N = 10时,那将是9 + 8 + ... = 45

相反,某些算法可能是N * N.当N = 10时,它将是100。

尽管如此,考虑到深拷贝或浅拷贝的成本,我同意这一点 在某些情况下,@帕特里克·佩里尼的出色表现会比这更好,甚至数量也是N * N.

编辑:

使用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

看起来更复杂,但使用与以前相同的想法。这没有不必要的内存分配或副本。

我关心的是效率,即更快的UI响应,更长的电池寿命,更小的内存占用等。如果我们提供有竞争力的话,避免不必要的内存分配和/或后台场景中由Swift自动完成的内存复制将至关重要产品。 ( - ;

答案 10 :(得分:0)

雨燕4

2行,快速解决方案:

public class MyOtherClass<T> where T : Base {...}

答案 11 :(得分:0)

extension Array where Element: Hashable {
     func similar() -> Self {
        var used = [Element: Bool]()

        return self.filter { used.updateValue(true, forKey: $0) != nil }
    }
}

答案 12 :(得分:0)

// find duplicate number in an array 
var arrNum = [1, 2, 3 , 3, 2, 5, 6, 2] 
let setOfNum = Set(Array(arrNum))
print(setOfNum)
<块引用>
Output: [6, 3, 5, 1, 2]
// find duplicate string in an array 
var arrStr = ["1", "2", "3" , "3", "2", "5", "6", "2"]  
let setOfStr = Set(Array(arrStr))
print(setOfNum)
<块引用>
Output: [6, 3, 5, 1, 2]

答案 13 :(得分:0)

let inputArray = [9820213496, 9546533545, 9820213496, 995543567]
var outputArray = [Int]()
for element in inputArray{
    if outputArray.contains(element){
        print("\(element) is Duplicate")
    }else{
        outputArray.append(element)
    }
}
print(outputArray) // print Array without duplication