【问题标题】:How do I remove duplicates from an array [duplicate]如何从数组中删除重复项[重复]
【发布时间】:2017-06-21 07:47:14
【问题描述】:

假设我有一个字符串数组:

let arrayOfStrings = ["a", "b", "a", "c", "a", "d"]

我将如何摆脱重复项?

【问题讨论】:

标签: arrays swift duplicates


【解决方案1】:

您可以使用数组函数contains(_:) 来检查一个元素是否已经是数组的一部分,但这相当慢,并且对于大型数组它不会很好地执行。 (1.) 最好将条目复制到Set 并使用Set 操作来查找和删除重复项。集合经过优化,可以快速测试集合成员资格,因此 if aSet.contains(item)if anArray.contains(item) 快很多。

如果您不关心保留项目的顺序,您可以简单地将您的数组复制到一个集合中,然后再返回一个数组。但是,这确实意味着结果数组中的项目将采用不同的顺序。

从字符串数组中删除重复项,同时保留顺序的函数可能如下所示:

func uniqueElementsFrom(array: [String]) -> [String] {
  //Create an empty Set to track unique items
  var set = Set<String>()
  let result = array.filter {
    guard !set.contains($0) else {
      //If the set already contains this object, return false
      //so we skip it
      return false
    }
    //Add this item to the set since it will now be in the array
    set.insert($0)
    //Return true so that filtered array will contain this item.
    return true
  }
  return result
}

如果你用这样的代码调用它:

let arrayOfStrings = ["a", "b", "a", "c", "a", "d"]
let uniqueStrings = uniqueElementsFrom(array:arrayOfStrings)
print("Unique elements from \(arrayOfStrings) = \n” + 
  “\(uniqueStrings)")

输出将是

来自 ["a", "b", "a", "c", "a", "d"] 的唯一元素 =

[“a”, “b”, “c”, “d”]

但是,该函数仅适用于字符串数组。如果我们可以编写一个可以从任何类型的数组中删除重复项的函数,那就太好了。

这是泛型的工作。但是有一个问题。集合只能包含符合Hashable 协议的对象,因为集合使用散列来更快地测试集合成员资格。

我们可以使用泛型重写uniqueElementsFrom(array:) 函数以获取符合Hashable 协议的任何数组。该代码如下所示:

func uniqueElementsFrom<T: Hashable>(array: [T]) -> [T] {
  var set = Set<T>()
  let result = array.filter {
    guard !set.contains($0) else {
      return false
    }
    set.insert($0)
    return true
  }
  return result
}

函数名称后面的&lt;T: Hashable&gt; 位表示“此函数的其余部分将引用未指定的类型 T。唯一可以确定的是类型 T 将符合 Hashable 协议。”

uniqueElementsFrom(array:) 函数的这种形式适用于任何元素为 Hashable 的数组。


(1.) 对于数组,contains(_:) 具有 O(n) 性能,因此循环遍历数组,测试数组以查看它是否包含每个具有 contains(_:) 的新元素具有性能这几乎是O(n^2),这真的,真的除了小数组之外的任何东西都不好。我很确定Setcontains(_:)函数具有恒定的时间性能,所以整个过程会有O(n)的性能。

【讨论】:

  • 如果我有一个对象数组,这会有帮助吗?我需要过滤对象内包含的相同经纬度?
  • @LohithKorupolu,是的,您可以使用相同的方法。 CLLocation 对象是 Equable,因此您可以使对象数组包含 CLLocation,并使用 == 比较它们。但是请注意,这些位置必须完全相同。如果您试图判断多个 GPS 读数是否代表同一个位置,则使用 == 比较位置将不起作用,因为这些位置会相差很小。
  • @DuncanC,非常感谢。此解决方案最好从数组中删除重复的字符串。
  • 其实我觉得 Jessy 在这个帖子里的回答:stackoverflow.com/questions/25738817/… 更加优雅和灵活。他建议对Sequence 进行两种不同的扩展,一种用于hashable 的序列,另一种用于equatable 的序列。 hashable 版本对于长序列来说会快很多,但至少你可以选择非散列。
  • @LohithKorupolu 我建议为 CLLocation 对象创建 == 的自定义实现,该对象使用“slop”或“epsilon”值,将非常接近的位置视为相同。您可以定义您的扩展使用的全局静态变量。计算“足够近”的一种简单方法是使用位置之间的毕达哥拉斯距离。然而,这并不允许当您接近两极时,经度线变得更近。
猜你喜欢
  • 2012-10-04
  • 2014-06-07
  • 2011-06-29
  • 2015-09-22
  • 2022-12-05
  • 2013-08-03
  • 2022-01-03
相关资源
最近更新 更多