JavaScript-查找数组的重复次数

时间:2018-10-29 19:25:14

标签: javascript arrays intersection repeat

我有以下数组:

let a = ["egg", "pepper", "salt", "bacon", "beer", "salt", "water", "beer", "egg"]
let b = ["egg", "salt", "beer"]

如何检查b中来自a的单词多少次?

在上述情况下,答案将是2次,因为来自b的所有单词都包含两次。但是,如果a如下:

let a = ["egg", "pepper", "salt", "bacon", "beer", "salt", "water", "beer"]

答案是1,因为egg仅包含一次。

在这里,时间效率是关键,因为我将处理包含超过10万个元素的列表。

7 个答案:

答案 0 :(得分:1)

您可以使用reduce方法:

let words = ["egg", "pepper", "salt", "bacon", "beer", "salt", "water", "beer", "egg"]

var initialValue = {};

var reducer = function(word, index){
	if(!word[index]){
		word[index] = 1;
	} else{
		word[index] = word[index] + 1;
	}
	return word;
}

var results = words.reduce(reducer, initialValue);

console.log(results);

答案 1 :(得分:1)

let a = ["egg", "pepper", "salt", "bacon", "beer", "salt", "water", "beer", "egg"]
let b = ["egg", "salt", "beer"]
let counts ={}

b.forEach(word=>{      
    counts[word] = a.filter(item => item ===word).length
});    

console.log(counts)

答案 2 :(得分:1)

这是一个非常简单的解决方案,其结果将列出第二个列表中的所有内容,对于不在数据中的内容包括零。

ab的长度总和中,性能应该几乎是线性的。 (a in o中可能存在一些难以测量的非线性,但是我不知道引擎内部使用的算法,所以我不确定。)

请注意,bs.reduce((o, b) => Object.assign(o, {[b]: 0}), {})仅被调用一次,以形成第一个reduce的初始累加器;这不是嵌套的减少。

const counts = (as, bs) => as.reduce(
  (o, a) => Object.assign(o, a in o ? {[a]: o[a] + 1} : {}),
  bs.reduce((o, b) => Object.assign(o, {[b]: 0}), {})
)

const a = ["egg", "pepper", "salt", "bacon", "beer", "salt", "water", "beer", "egg"]
const b = ["egg", "salt", "beer", "tofu"]

console.log(counts(a, b))

但是实际性能可能会低于某些手动滚动的forwhile循环。 reduce的表现根本不如它们。

更新

这实际上并没有回答所问的问题。我误解了这个问题。更新的版本是

const minMatch = (as, bs) => Math.min(...Object.values(as.reduce(
  (o, a) => Object.assign(o, a in o ? {[a]: o[a] + 1} : {}),
  bs.reduce((o, b) => Object.assign(o, {[b]: 0}), {})
)))

const a = ["egg", "pepper", "salt", "bacon", "beer", "salt", "water", "beer", "egg"]
const b = ["egg", "salt", "beer"]

console.log(minMatch(a, b))

答案 3 :(得分:1)

使用Array.reduce()迭代数组a。将数组b转换为Map,并将其用作reduce的初始值。

如果Map中存在数组a中的一项,则增加该值。如果没有,请忽略它。完成后,通过Math.min()分布地图的值:

const a = ["egg", "pepper", "salt", "bacon", "beer", "salt", "water", "beer", "egg"]
const b = ["egg", "salt", "beer"]

const result = Math.min(
  ...a.reduce((m, s) =>
      m.has(s) ? m.set(s, (m.get(s) || 0) + 1) : m
    , new Map(b.map(s => [s, 0]))
  ).values()
);

console.log(result);

答案 4 :(得分:0)

该方法可以是在遍历数组A时构造一个哈希映射,而在遍历数组B时访问该哈希映射(请参见下面的代码)

let a = ["egg", "pepper", "salt", "bacon", "beer", "salt", "water", "beer", "egg"]
let b = ["egg", "salt", "beer"]
let hashMap = {};

for(let element in a){
  if(!hashMap[a[element]])
     hashMap[a[element]] = 0;
  hashMap[a[element]]++;
}

var minVal = a.length;
for(let element in b){
  if(hashMap[b[element]])
     minVal = Math.min(minVal, hashMap[b[element]]);
}
console.log(minVal);

答案 5 :(得分:0)

这应该有效

let a = ["egg", "pepper", "salt", "bacon", "beer", "salt", "water", "beer", "salt"];
let b = ["egg", "salt"];

const products = a.reduce((result, current) => {
  b.forEach(word => {
    if (word === current) {
      result[word] = result[word] ? result[word] + 1 : 1;
    }
  })
  return result;
}, {});

console.log(products); // { egg: 1, salt: 3 }

答案 6 :(得分:0)

使用数字for循环将a简化为普通对象:

let a = ["egg", "pepper", "salt", "bacon", "beer", "salt", "water", "beer", "egg"]
let b = ["egg", "salt", "beer"]

const keys = b.reduce((o, k) => Object.assign(o, { [k]: true }), {})
const { length } = a
const values = {}

for (let i = 0; i < length; i++) {
  const key = a[i]
  
  if (key in keys) {
    if (key in values) {
      values[key]++
    } else {
      values[key] = 1
    }
  }
}

console.log(values)

数字for循环比reduceforEach之类的Array方法要快,并且通常比for...offor...in要快不使用iterators或反射来枚举数组的键。

keys对象的作用是根据b的大小将查找从O(n)减少到〜O(1),使您的整体复杂度约为 O(n) 。如果b也很大,则也可以使用数字for循环来创建keys,并注意查找可能会从〜O(1)恶化为O(log(n)),这会导致将使您的总时间复杂度为 O(n log(n))