如何获得数组中的唯一值
我怎样才能得到一个数组中的唯一值列表? 我是否总是要使用第二个数组,或者在JavaScript中有类似于java的hashmap的东西吗?
我将只使用JavaScript和jQuery 。 没有额外的库可以使用。
因为我在@ Rocket的回答中继续讨论这个问题,所以我不妨提供一个不使用库的例子。 这需要两个新的原型function, contains
和unique
Array.prototype.contains = function(v) { for(var i = 0; i < this.length; i++) { if(this[i] === v) return true; } return false; }; Array.prototype.unique = function() { var arr = []; for(var i = 0; i < this.length; i++) { if(!arr.includes(this[i])) { arr.push(this[i]); } } return arr; }
你可以这样做:
var duplicates = [1,3,4,2,1,2,3,8]; var uniques = duplicates.unique(); // result = [1,3,4,2,8]
为了获得更高的可靠性,可以用MDN的indexOf
shimreplacecontains
,并检查每个元素的indexOf
是否等于-1: https : //developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
或者对于那些正在寻找一个单行(简单和function), 与目前的浏览器兼容的人来说 :
var a = ["1", "1", "2", "3", "3", "1"]; var unique = a.filter(function(item, i, ar){ return ar.indexOf(item) === i; });
更新18-04-17
看起来好像“Array.prototype.includes”现在在主线浏览器的最新版本中具有广泛的支持( 兼容性 )
更新29/07/2015:
在浏览器中有计划支持一个标准化的“Array.prototype.includes”方法,虽然这个方法并没有直接回答这个问题, 往往是相关的。
用法:
["1", "1", "2", "3", "3", "1"].includes("2"); // true
Pollyfill( 浏览器支持 , 来自mozilla ):
// https://tc39.github.io/ecma262/#sec-array.prototype.includes if (!Array.prototype.includes) { Object.defineProperty(Array.prototype, 'includes', { value: function(searchElement, fromIndex) { // 1. Let O be ? ToObject(this value). if (this == null) { throw new TypeError('"this" is null or not defined'); } var o = Object(this); // 2. Let len be ? ToLength(? Get(O, "length")). var len = o.length >>> 0; // 3. If len is 0, return false. if (len === 0) { return false; } // 4. Let n be ? ToInteger(fromIndex). // (If fromIndex is undefined, this step produces the value 0.) var n = fromIndex | 0; // 5. If n ≥ 0, then // a. Let k be n. // 6. Else n < 0, // a. Let k be len + n. // b. If k < 0, let k be 0. var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0); // 7. Repeat, while k < len while (k < len) { // a. Let elementK be the result of ? Get(O, ! ToString(k)). // b. If SameValueZero(searchElement, elementK) is true, return true. // c. Increase k by 1. // NOTE: === provides the correct "SameValueZero" comparison needed here. if (o[k] === searchElement) { return true; } k++; } // 8. Return false return false; } }); }
一个class轮,纯粹的JavaScript
使用ES6语法
list = list.filter((x, i, a) => a.indexOf(x) == i)
x --> item in array i --> index of item a --> array reference, (in this case "list")
使用ES5语法
list = list.filter(function (x, i, a) { return a.indexOf(x) == i; });
浏览器兼容性 :IE9 +
如果你想保留原始数组,
你需要第二个数组来包含first-
大多数浏览器都有Array.prototype.filter
:
var unique= array1.filter(function(itm, i){ return array1.indexOf(itm)== i; // returns true for only the first instance of itm }); //if you need a 'shim': Array.prototype.filter= Array.prototype.filter || function(fun, scope){ var T= this, A= [], i= 0, itm, L= T.length; if(typeof fun== 'function'){ while(i<L){ if(i in T){ itm= T[i]; if(fun.call(scope, itm, i, T)) A[A.length]= itm; } ++i; } } return A; } Array.prototype.indexOf= Array.prototype.indexOf || function(what, i){ if(!i || typeof i!= 'number') i= 0; var L= this.length; while(i<L){ if(this[i]=== what) return i; ++i; } return -1; }
这里有一个更清洁的ES6解决scheme,我看不包括在这里。 它使用Set和spread运算符 : ...
var a = [1, 1, 2]; [... new Set(a)]
其中返回[1, 2]
使用第二个数组的短而甜的解决scheme
var axes2=[1,4,5,2,3,1,2,3,4,5,1,3,4]; var distinct_axes2=[]; for(var i=0;i<axes2.length;i++) { var str=axes2[i]; if(distinct_axes2.indexOf(str)==-1) { distinct_axes2.push(str); } } console.log("distinct_axes2 : "+distinct_axes2); // distinct_axes2 : 1,4,5,2,3
现在,您可以使用ES6的Set数据types将您的数组转换为唯一的Set。 然后,如果你需要使用数组方法,你可以把它变成一个数组:
var arr = ["a", "a", "b"]; var uniqueSet = new Set(arr); // {"a", "b"} var uniqueArr = Array.from(uniqueSet); // ["a", "b"] //Then continue to use array methods: uniqueArr.join(", "); // "a, b"
使用jQuery,这是我做的一个数组独特的function:
Array.prototype.unique = function () { var arr = this; return $.grep(arr, function (v, i) { return $.inArray(v, arr) === i; }); } console.log([1,2,3,1,2,3].unique()); // [1,2,3]
你只需要香草JS来find独一无二的Array.some和Array.reduce。 ES2015语法只有62个字符。
a.reduce((c, v) => b.some(w => w === v) ? c : c.concat(v)), b)
在IE9 +和其他浏览器中支持Array.some和Array.reduce。 只需将常规function的胖箭头function更改为支持不支持ES2015语法的浏览器。
var a = [1,2,3]; var b = [4,5,6]; // .reduce can return a subset or superset var uniques = a.reduce(function(c, v){ // .some stops on the first time the function returns true return (b.some(function(w){ return w === v; }) ? // if there's a match, return the array "c" c : // if there's no match, then add to the end and return the entire array c.concat(v)}), // the second param in .reduce is the starting variable. This is will be "c" the first time it runs. b);
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects /arrays/缩小
在Javascript中不是原生的,但有很多库有这种方法。
_.uniq(array)
的_.uniq(array)
( 链接 )工作得很好( 源 )。
上述多数解决scheme运行时间复杂度高。
这里是使用reduce
的解决scheme,并且可以在O(n)时间内完成这项工作。
Array.prototype.unique = Array.prototype.unique || function() { var arr = []; this.reduce(function (hash, num) { if(typeof hash[num] === 'undefined') { hash[num] = 1; arr.push(num); } return hash; }, {}); return arr; } var myArr = [3,1,2,3,3,3]; console.log(myArr.unique()); //[3,1,2];
目前解决scheme唯一的问题是效率。 如果你担心这一点(你可能应该),你需要避免嵌套循环:为*,筛选* indexOf,grep * inArray,他们都迭代数组多次。 你可以用这样或者这样的解决scheme实现一个单一的循环
这个问题的另一个想法。 这是我做了什么,用更less的代码来实现这一点。
var distinctMap = {}; var testArray = ['John', 'John', 'Jason', 'Jason']; for (var i = 0; i < testArray.length; i++) { var value = testArray[i]; distinctMap[value] = ''; }; var unique_values = Object.keys(distinctMap);
Array.prototype.unique = function () { var dictionary = {}; var uniqueValues = []; for (var i = 0; i < this.length; i++) { if (dictionary[this[i]] == undefined){ dictionary[this[i]] = i; uniqueValues.push(this[i]); } } return uniqueValues; }
function findUnique(arr) { var result = []; arr.forEach(function (d) { if (result.indexOf(d) === -1) result.push(d); }); return result; } var unique = findUnique([1, 2, 3, 1, 2, 1, 4]); // [1,2,3,4]
ES6方式:
const uniq = (arr) => (arr.filter((item, index, arry) => (arry.indexOf(item) === index)));
我已经在纯JS中试过这个问题。 我遵循以下步骤1.对给定的数组进行sorting,2.遍历sorting后的数组,3.使用当前值validation上一个值和下一个值
// JS var inpArr = [1, 5, 5, 4, 3, 3, 2, 2, 2,2, 100, 100, -1]; //sort the given array inpArr.sort(function(a, b){ return ab; }); var finalArr = []; //loop through the inpArr for(var i=0; i<inpArr.length; i++){ //check previous and next value if(inpArr[i-1]!=inpArr[i] && inpArr[i] != inpArr[i+1]){ finalArr.push(inpArr[i]); } } console.log(finalArr);
演示
我只是想,如果我们可以使用线性search来消除重复:
JavaScript: function getUniqueRadios() { var x=document.getElementById("QnA"); var ansArray = new Array(); var prev; for (var i=0;i<x.length;i++) { // Check for unique radio button group if (x.elements[i].type == "radio") { // For the first element prev will be null, hence push it into array and set the prev var. if (prev == null) { prev = x.elements[i].name; ansArray.push(x.elements[i].name); } else { // We will only push the next radio element if its not identical to previous. if (prev != x.elements[i].name) { prev = x.elements[i].name; ansArray.push(x.elements[i].name); } } } } alert(ansArray);
}
HTML:
<body> <form name="QnA" action="" method='post' "> <input type="radio" name="g1" value="ANSTYPE1"> good </input> <input type="radio" name="g1" value="ANSTYPE2"> avg </input> <input type="radio" name="g2" value="ANSTYPE3"> Type1 </input> <input type="radio" name="g2" value="ANSTYPE2"> Type2 </input> <input type="submit" value='SUBMIT' onClick="javascript:getUniqueRadios()"></input> </form> </body>
这里是解决问题的单线解决scheme:
var seriesValues = [120, 120, 120, 120]; seriesValues = seriesValues.filter((value, index, seriesValues) => (seriesValues.slice(0, index)).indexOf(value) === -1); console.log(seriesValues);
我有内置的JQuery独特的function。
uniqueValues= jQuery.unique( duplicateValues );
更多的你可以参考jQuery API文档。