JavaScript:删除数组中的重复项

JavaScript:删除数组中的重复项,javascript,arrays,hash,multidimensional-array,duplicates,Javascript,Arrays,Hash,Multidimensional Array,Duplicates,目前正在使用JavaScript,我需要遍历数组数组以确定是否存在任何重复的数组,然后删除这些重复的数组。在这种情况下,运行时至关重要,所以我想知道最有效的方法是什么 在这种情况下,是否需要使用哈希表?其范围是对每个序列进行散列,然后使用散列来确定该序列是否再次发生。因此,每个序列都是主数组中的一个数组,任何重复序列都是同一数组中的其他数组。此外,极为重要的是,所有单个数组都保持其自身的有序性(即单个数组中的元素必须始终保持其位置)。此外,单个数组中的所有元素都是字符串值 示例:假设有一个数组A

目前正在使用JavaScript,我需要遍历数组数组以确定是否存在任何重复的数组,然后删除这些重复的数组。在这种情况下,运行时至关重要,所以我想知道最有效的方法是什么

在这种情况下,是否需要使用哈希表?其范围是对每个序列进行散列,然后使用散列来确定该序列是否再次发生。因此,每个序列都是主数组中的一个数组,任何重复序列都是同一数组中的其他数组。此外,极为重要的是,所有单个数组都保持其自身的有序性(即单个数组中的元素必须始终保持其位置)。此外,单个数组中的所有元素都是字符串值

示例:假设有一个数组A,其元素依次为以下数组:

A[0] = ["one", "two", "three", "four"]
A[1] = ["two", "one", "three", "four"]
A[2] = ["one", "two", "three", "four"]

在上面的示例中,[0]和[2]是重复的,因此函数应该返回[0]和[1],以便同一数组只有一个实例

保留一个对象,其中键是每个数组的连接元素。如果找不到键,请将数组添加到输出数组,然后将键添加到对象

var hash = {};
var out = [];
for (var i = 0, l = A.length; i < l; i++) {
  var key = A[i].join('|');
  if (!hash[key]) {
    out.push(A[i]);
    hash[key] = 'found';
  }
}
var hash={};
var out=[];
对于(变量i=0,l=A.length;i

好的,让我们先看看简单解决方案的复杂性: 如果有n个数组,每个数组最多有k个条目,则需要进行
O(n^2*k)
比较,因为对于这n个数组中的每一个,都必须将其与n-1个其他数组进行比较,每个数组都有k个比较。空间复杂度为
O(n*k)

因此,如果您愿意交换空间以获得更好的性能,您可以执行以下操作: (简短的免责声明:我假设您的所有数组都有相同数量的k元素,这是您的问题所指出但未得到批准的。)

一个接一个地遍历数组,选择我们假设的第一个元素是
a
。 使用哈希映射来验证是否将此元素视为之前的第一个元素。如果不是,请创建一个树状结构,将
a
作为其根,将其存储在哈希映射中的
a
下,并将其设置为当前节点。 现在,对于当前数组中的每个后续条目,检查当前节点是否有此类子节点。因此,如果第二个条目是
b
,则将
b
添加为a的子条目

您的树现在看起来是这样的:(从左到右:根到子对象)

a-b

c
作为第三个条目的工作原理完全相同:

a-b-c

现在我们向前跳,看看数组
[a,c,d]
。 您首先遇到元素
a
的树。对于第二个元素,检查
c
是否已经是a的子元素。如果没有,请添加:

  - b - c
a
  - c
下一个条目也是如此:

  - b - c
a
  - c - d
现在让我们看看当我们检查之前看到的数组时会发生什么:
[a,b,c]

首先,我们检查
a
,查看已经有一个树,并从哈希映射中获取它。接下来,我们注意到
a
有一个名为
b
的子级,因此我们下降到
b
。现在,对于最后一个条目,我们看到它也在那里,告诉我们我们遇到了一个可以删除的重复项

很抱歉我临时画了这幅画,我希望我能把这个想法表达清楚。 它只需遍历每个阵列一次,以非冗余方式存储它。 因此,时间复杂度将是
O(n*k)
。使用的空间会增加,但受到
O(n*k)
的限制,因为最坏的情况是没有数组共享任何前缀,这会导致相同的空间复杂度

希望我没有忽略什么

单行线 我假设您的字符串不包含
字符。如果包含,则两次将
r[a]
更改为
r[a.join(“|”)]
(其中
是任意分隔符)或使用
r[a.map(x=>x.length+”,“+x)]
允许字符串中的所有字符。这是

解释


r={}
中,我们设置了一个临时对象。在过滤函数
a=>…
中,仅用于在参数
r={}
中声明一次空的临时对象。在函数
a=>…
中,在
a
中,我们有当前的
a
元素。JS对
r[a]
中的字符串进行隐式转换
a
。然后在
中!(r[a]=++r[a]|0)
如果元素
a
第一次出现,我们增加出现元素
a
的计数器,并返回true(作为过滤函数值)

问得好,但你的尝试在哪里?考虑到时间复杂度至关重要,在实现之前理想的解决方案是什么。这里的效率有两层含义:如果编码最快的算法需要一天时间,但你只检查100个数组,我不确定这是否有效。也许一个双
for
循环就足够了。A和A[n]的大小是多少?效率意味着算法运行所需的时间,而不是编码算法所需的时间。因此,首先,它们不是重复的。它们是碰巧序列化为相同的单个数组文本,但它们不是
相同的
数组,如
['one']=['one'];//错误
。您可以编写一个函数,通过lodash的
..isEqual
-来比较它们,或者您可以使用普通javascript来进行比较,但它不是一个2行程序。特别是当实际数组比字符串列表更复杂时。如果只是字符串/原语,则可以与
item.join(',')进行比较我建议使用不同的“连接”字符。理想情况下,它应该是在输入数组的字符串中找不到的。如果它可以使用JSON进行任何输入。stringify是一个选项。
['foo','bar']
['foobar']不同A.filter((r={},a=>!(r[a]=++r[a]|0)))