Arrays 如何从阵列中删除重复项

Arrays 如何从阵列中删除重复项,arrays,swift,duplicates,Arrays,Swift,Duplicates,假设我有一个字符串数组: let arrayOfStrings = ["a", "b", "a", "c", "a", "d"] 如何消除重复项?您可以使用数组函数contains(:)来检查元素是否已经是数组的一部分,但这相当慢,对于大型数组,它的性能不好。(1.)最好将条目复制到Set中,并使用Set操作查找并删除重复项。集合经过优化,可以快速测试集合成员资格,因此如果aSet.contains(item)比如果anArray.contains(item)快得多 如果不想保留项目的顺序,只

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

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

如何消除重复项?

您可以使用数组函数
contains(:)
来检查元素是否已经是数组的一部分,但这相当慢,对于大型数组,它的性能不好。(1.)最好将条目复制到
Set
中,并使用
Set
操作查找并删除重复项。集合经过优化,可以快速测试集合成员资格,因此如果aSet.contains(item)比如果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)")
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
}
输出将是

来自[“a”、“b”、“a”、“c”、“a”、“d”]的独特元素=

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

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

这是泛型药的工作。然而,有一个陷阱。集合只能包含符合可哈希协议的对象,因为集合使用哈希可以更快地测试集合成员资格

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

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)")
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
}
func uniquelementsfrom(数组:[T])->[T]{
var set=set()
让result=array.filter{
守卫!设置。包含($0)个其他项{
返回错误
}
set.insert($0)
返回真值
}
返回结果
}
函数名后的
位表示“此函数的其余部分将引用未指定的类型T。唯一可以确定的是类型T将符合哈希协议。”

这种形式的
uniquelementsfrom(array:)
函数将在任何数组中使用
可散列的元素



(1.)对于数组,
contains(:)
具有
O(n)
性能,因此在一个数组中循环,测试该数组是否包含
contains(:)
的每个新元素,看看它是否具有几乎
O(n^2)
的性能,这对于除了小数组之外的任何东西来说都是非常糟糕的。我很确定
Set
contains(:)
函数具有恒定的时间性能,因此整个过程将具有
O(n)
性能。

还有:这样好吗?让uniqueArray=Array(Set(arrayOfStrings))如果我有一个对象数组,这会有帮助吗?我需要过滤物体内部包含的相同纬度经度?@LohithKorupolu,是的,你可以使用相同的方法。CLLocation对象是相等的,因此您可以使对象数组包含CLLocation,并使用
==
对它们进行比较。但是请注意,位置必须完全相同。如果您试图判断多个GPS读数是否代表同一位置,则使用
=
比较位置将不起作用,因为位置会略有不同。@Duncac,非常感谢。这个解决方案最好是从数组中删除重复的字符串。实际上,我认为Jessy在这个帖子中的回答是:更优雅、更灵活。他建议对
序列
进行两种不同的扩展,一种用于可哈希的序列,另一种用于可相等的序列。对于长序列,
hashable
版本会快得多,但至少您可以选择非hashable。@LohithKorupolu我建议为CLLocation对象创建==的自定义实现,该对象使用“slop”或“epsilon”值来处理非常接近的位置。您可以定义扩展使用的全局静态变量。计算“足够近”的简单方法是使用位置之间的毕达哥拉斯距离。然而,这并没有考虑到这样一个事实,即当你接近两极时,经线会变得更近。