查找两个数组是不是在数组中重复,然后选择它们
Posted
技术标签:
【中文标题】查找两个数组是不是在数组中重复,然后选择它们【英文标题】:Find if two arrays are repeated in array and then select them查找两个数组是否在数组中重复,然后选择它们 【发布时间】:2019-04-26 10:21:10 【问题描述】:我在主/父数组中有多个数组,如下所示:
var array = [[1, 17], [1, 17], [1, 17], [2, 12], [5, 9], [2, 12], [6, 2], [2, 12]];
为了便于阅读,这里是数组:
[1, 17]
[1, 17]
[1, 17]
[2, 12]
[5, 9]
[2, 12]
[6, 2]
[2, 12]
[2, 12]
我想选择重复 3 次或更多次 (> 3) 的数组并将其分配给一个变量。所以在这个例子中,var repeatedArrays
将是 [1, 17]
和 [2, 12]
。
所以这应该是最终的结果:
console.log(repeatedArrays);
>>> [[1, 17], [2, 12]]
我发现了类似的 here,但它使用 underscore.js 和 lodash。
我如何使用 javascript 甚至 jquery(如果需要)?
【问题讨论】:
您可以将它们与它们的 JSON 值进行比较,但是,[1, 17]
不会匹配 [17, 1]
您可以通过单击左侧的灰色大复选按钮来接受一个答案(如果对您有帮助)。如果您希望可以通过单击上方灰色三角形为任何好的答案的任何作者添加 +10 分
【参考方案1】:
试试这个
array.filter(( r=, a=>!(2-(r[a]=++r[a]|0)) ))
var array = [[1, 17], [1, 17], [1, 17], [2, 12], [5, 9], [2, 12], [6, 2], [2, 12]];
var r= array.filter(( r=, a=>!(2-(r[a]=++r[a]|0)) ))
console.log(JSON.stringify(r));
时间复杂度O(n)(一个数组通过过滤函数)。灵感来自Nitish 答案。
说明
(r=, a=>...)
将返回逗号后的最后一个表达式(即a=>...
)(例如(5,6)==6
)。在r=
中,我们设置了一次临时对象,我们将在其中存储唯一键。在a
中的过滤函数a=>...
中,我们有当前array
元素。在r[a]
JS 中将a
隐式转换为字符串(例如1,17
)。然后在!(2-(r[a]=++r[a]|0))
中,我们增加出现元素a
的计数器,如果元素a
出现3 次,则返回true(作为过滤函数值)。如果r[a]
未定义,则++r[a]
返回NaN
,然后返回NaN|0=0
(还有number|0=number
)。 r[a]=
初始化第一个计数器值,如果我们省略它,++
只会将 NaN
设置为不可递增的 r[a]
(因此我们需要在 init 处置零)。如果我们删除2-
作为结果,我们将得到没有重复的输入数组 - 或者我们也可以通过a=>!(r[a]=a in r)
得到它。如果我们将2-
更改为1-
,我们将得到只有重复的数组.
更新
甚至可以编写基于@ken comment 的更短版本(它应该始终与数字数组一起使用)。 @ken 代码的原始较长版本位于 sn-p 中,并展示了 @ken 如何巧妙地使用 .filter
的第二个参数来避免使用全局变量 r
。
array.filter(a=>!(2-(this[a]=++this[a]|0)))
var array = [[1, 17], [1, 17], [1, 17], [2, 12], [5, 9], [2, 12], [6, 2], [2, 12]];
var r= array.filter(a=>!(2-(this[a]=++this[a]|0)), )
console.log(JSON.stringify(r));
【讨论】:
有些人真的很喜欢挑战极限。尊重。 B) 我只花了大约 1/2 小时试图了解您所做的事情。现在我明白了,我更加珍惜它。如果可以的话,我会给你一个赏金。如果其他人对此感到震惊,我将其分解为多个部分,并提供了一个帮助示例来尝试在这里进行研究:jsfiddle.net/drpfe3hm/3 没有逗号返回和滥用第二个参数到Array#filter
(thisArg
):array.filter(a=>!(2-(this[a]=++this[a]|0)), )
@ken - 感谢您的改进 - 很好 - 我认为这也可以写得更短array.filter(a=>!(2-(this[a]=++this[a]|0)))
@ken 知道我很难过。我宁愿不知道像 Vyxal 和 Jelly 这样的东西存在。 :D【参考方案2】:
您可以使用带有字符串化数组和计数的Map
,然后按计数过滤并恢复数组。
var array = [[1, 17], [1, 17], [1, 17], [2, 12], [5, 9], [2, 12], [6, 2], [2, 12]],
result = Array
.from(array.reduce(
(map, array) =>
(json => map.set(json, (map.get(json) || 0) + 1))
(JSON.stringify(array)),
new Map
))
.filter(([, count]) => count > 2)
.map(([json]) => JSON.parse(json));
console.log(result);
.as-console-wrapper max-height: 100% !important; top: 0;
使用所需数量的地图过滤。
var array = [[1, 17], [1, 17], [1, 17], [2, 12], [5, 9], [2, 12], [6, 2], [2, 12]],
result = array.filter(
(map => a =>
(json =>
(count => map.set(json, count) && !(2 - count))
(1 + map.get(json) || 1)
)
(JSON.stringify(a))
)
(new Map)
);
console.log(result);
.as-console-wrapper max-height: 100% !important; top: 0;
独一无二!
var array = [[1, 17], [1, 17], [1, 17], [2, 12], [5, 9], [2, 12], [6, 2], [2, 12]],
result = array.filter(
(s => a => (j => !s.has(j) && s.add(j))(JSON.stringify(a)))
(new Set)
);
console.log(result);
.as-console-wrapper max-height: 100% !important; top: 0;
【讨论】:
太棒了!这行得通!有没有办法从原始数组中删除重复的数组?所以var array
的最终输出将是[[1, 17], [2, 12], [5, 9], [6, 2]]
。我试过filter()
和indexOf()
但没用
对于该任务,您可以使用Set
而不是Map
。
你能编辑你的答案并给我看吗?我用has()
吗?
@TimmyBalk 只需删除 .filter(([, count]) => count > 2)
行 - 不要更改任何其他内容
@KamilKiełczewski 太棒了!太感谢了。我现在要研究filter()
函数,再次感谢 Nina 和 Kamil。但我假设删除 .filter
行与 Nina 所说的不同?【参考方案3】:
您可以像下面这样使用Object.reduce
、Object.entries
var array = [[1, 17], [1, 17], [1, 17], [2, 12], [5, 9], [2, 12], [6, 2], [2, 12]];
let res = Object.entries(
array.reduce((o, d) =>
let key = d.join('-')
o[key] = (o[key] || 0) + 1
return o
, ))
.flatMap(([k, v]) => v > 2 ? [k.split('-').map(Number)] : [])
console.log(res)
OR 可能只是Array.filters
var array = [[1, 17], [1, 17], [1, 17], [1, 17], [2, 12], [5, 9], [2, 12], [6, 2], [2, 12]];
let temp =
let res = array.filter(d =>
let key = d.join('-')
temp[key] = (temp[key] || 0) + 1
return temp[key] == 3
)
console.log(res)
【讨论】:
第一次剪断不符合要求(返回元素是字符串而不是数字) - 但第二次剪断很棒,+1 谢谢@KamilKiełczewski。更新了第一个 sn-p 以返回 Numbers。【参考方案4】:换一种方式,您可以先对列表进行排序,然后循环一次并提取出满足您要求的元素。即使使用排序,这也可能比从数组中对键进行字符串化更快:
var arr = [[1, 17], [1, 17], [1, 17], [2, 12], [5, 9], [2, 12], [6, 2], [2, 12]]
arr.sort((a, b) => a[0] - b[0] || a[1] - b[1])
// define equal for array
const equal = (arr1, arr2) => arr1.every((n, j) => n === arr2[j])
let GROUP_SIZE = 3
first = 0, last = 1, res = []
while(last < arr.length)
if (equal(arr[first], arr[last])) last++
else
if (last - first >= GROUP_SIZE) res.push(arr[first])
first = last
if (last - first >= GROUP_SIZE) res.push(arr[first])
console.log(res)
【讨论】:
有趣的方法,但它真的更快吗? @TimmyBalk 这不是对 JSON 方法的批评——我认为这很好,但如果我的测试是正确的,它会更慢(至少在我的浏览器上)。这是一个 jsperf 测试:jsperf.com/2json-v-sort-loop【参考方案5】:您也可以使用单个 Array.reduce
执行此操作,如果长度等于 3,您将只推送到 result
属性:
var array = [[1, 17], [1, 17], [1, 17], [1, 17], [2, 12], [5, 9], [2, 12], [6, 2], [2, 12]];
console.log(array.reduce((r,c) =>
let key = c.join('-')
r[key] = (r[key] || 0) + 1
r[key] == 3 ? r.result.push(c) : 0 // if we have a hit push to result
return r
, result: []).result) // print the result property
【讨论】:
【参考方案6】:ES6:
const repeatMap =
array.forEach(arr =>
const key = JSON.stringify(arr)
if (repeatMap[key])
repeatMap[key]++
else
repeatMap[key] = 1
)
const repeatedArrays = Object.keys(repeatMap)
.filter(key => repeatMap[key] >= 3)
.map(key => JSON.parse(key))
【讨论】:
以上是关于查找两个数组是不是在数组中重复,然后选择它们的主要内容,如果未能解决你的问题,请参考以下文章