如何防止向JavaScript数组中添加重复的键

51

我发现很多相关的问题和答案都谈论了for...in循环和使用hasOwnProperty,但是我所做的一切都不能正常工作。我想要做的就是检查一个键是否存在于数组中,如果不存在就添加。

我从一个空数组开始,然后随着jQuery对页面进行扫描,添加键。

最初,我希望像下面这样简单的代码能够正常工作:(使用通用名称)

if (!array[key])
   array[key] = value;

不行。我接着做了以下事情:

for (var in array) {
   if (!array.hasOwnProperty(var))
      array[key] = value;
}

也尝试过:

if (array.hasOwnProperty(key) == false)
   array[key] = value;

这些方法都没有起作用。要么什么都没有添加到数组中,要么我尝试的方法和简单地声明array[key] = value没有什么区别。为什么一个看起来很简单的事情变得如此困难。有什么建议可以让它正常工作吗?


3
你是在尝试使用Array还是Object - thecodeparadox
ES6现在具有native Set - Efren
8个回答

48

一般来说,这更适合使用对象完成,因为JavaScript实际上没有关联数组:

var foo = { bar: 0 };

然后使用in检查键是否存在:

if ( !( 'bar' in foo ) ) {
    foo['bar'] = 42;
}

正如下面的评论所指出的那样,这种方法仅在您的键是字符串或可表示为字符串(例如数字)的项目时才有用。


2
假设您的值是字符串或可表示为唯一字符串(包括数字)。 - Phrogz
1
@Phrogz 绝对正确。对于楼主来说是很好的建议。 - Sampson
3
谢谢Jonathan。我终于明白了我错在哪里。我本来要说你的答案也没有帮上忙,但是经过更多的探索,我很高兴地说它完美地解决了我的问题。感谢你关于对象的提示,我会在以后记住的。 - iamsar

42
var a = [1,2,3], b = [4,1,5,2];

b.forEach(function(value){
  if (a.indexOf(value)==-1) a.push(value);
});

console.log(a);
// [1, 2, 3, 4, 5]

如果需要更多细节,请查阅Array.indexOf

如果您想依赖于jQuery,则应使用jQuery.inArray

$.each(b,function(value){
  if ($.inArray(value,a)==-1) a.push(value);
});

如果你的所有值都可以简单且唯一地表示为字符串,你应该使用一个对象而不是数组,这可能会带来巨大的速度提升(如由@JonathanSampson在答案中所述)。


2
此外,使用 indexOf 的问题在于它本身会产生一个循环... 这会导致 Schlemiel the painter's algorithm ,随着数组中每个项目的添加而变慢。 - Stijn de Witt

25

在ES6中,提供了一种更好的选择,即使用Sets。因此,如果您需要一个不应添加重复项的数组,则建议使用Sets而不是声明Arrays。

var array = new Set();
array.add(1);
array.add(2);
array.add(3);

console.log(array);
// Prints: Set(3) {1, 2, 3}

array.add(2); // does not add any new element

console.log(array);
// Still Prints: Set(3) {1, 2, 3}

2
只能使用基本类型,所以集合非常有限。 - Erik Philips
6
根据 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Set: Set 对象允许您存储任何类型的唯一值,无论是原始值还是对象引用 - VanagaS
3
它接受任何值,但无法评估非基元类型的相等性。http://jsfiddle.net/poLd7tk6/ - gunwin
从我看到的情况来看,set 返回的是一个对象而不是一个数组。 - Okiemute Gold

5

这里有一个使用展开运算符的简单方法。

这段代码会产生重复项:

let colors = ['red', 'orange', 'yellow'];
let moreColors = ['orange', 'green'];

// uh oh! this gives us 'orange' twice
let mergedColors = [...colors, ...moreColors];

因此,您可以在合并数组的同时过滤和删除它们。

let mergedColors = [...colors, ...moreColors.filter(c => !colors.includes(c)) ];

1

0
function check (list){
    var foundRepeatingValue = false;
    var newList = [];
    for(i=0;i<list.length;i++){
        var thisValue = list[i];
        if(i>0){
            if(newList.indexOf(thisValue)>-1){
                foundRepeatingValue = true;
                console.log("getting repeated");
                return true;
            }
       } newList.push(thisValue);
    } return false;
}

 

var list1 = ["dse","dfg","dse"];
check(list1);

输出:

getting repeated
true

0

逻辑有误。请考虑以下内容:

x = ["a","b","c"]
x[0]     // "a"
x["0"]   // "a"
0 in x   // true
"0" in x // true
x.hasOwnProperty(0)   // true
x.hasOwnProperty("0") // true

没有必要循环检查(或数组的索引)是否存在。现在,是另一回事...

编码愉快!


-1

let x = "farceus";
let y = "character";

const commonCharacters = function (string1, string2) {
  let duplicateCharacter = "";
  for (let i = 0; i < string1.length; i += 1) {
    if (duplicateCharacter.indexOf(string1[i]) === -1) {
      if (string2.indexOf(string1[i]) !== -1) {
        duplicateCharacter += string1[i];
      }
    }
  }
  return [...duplicateCharacter];
};


console.log(commonCharacters(x, y));


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接