javascript - has - omitby lodash




從JS數組中刪除重複的值 (20)

像這樣使用Array.filter()

var actualArr = ['Apple', 'Apple', 'Banana', 'Mango', 'Strawberry', 'Banana'];

console.log('Actual Array: ' + actualArr);

var filteredArr = actualArr.filter(function(item, index) {
  if (actualArr.indexOf(item) == index)
    return item;
});

console.log('Filtered Array: ' + filteredArr);

這可以縮短在ES6到

actualArr.filter((item,index,self) => self.indexOf(item)==index);

HereArray.filter()很好的解釋

這個問題在這裡已經有了答案:

我有一個非常簡單的JavaScript數組,可能包含或不包含重複項。

names = new Array("Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl");

我需要刪除重複項並將唯一值放入新數組中。

我可以指出我嘗試過的所有代碼,但我認為這是無用的,因為它們不起作用。 我也接受jQuery解決方案。

類似的問題:


“聰明”但天真的方式

uniqueArray = a.filter(function(item, pos) {
    return a.indexOf(item) == pos;
})

基本上,我們遍歷數組,並為每個元素檢查數組中該元素的第一個位置是否等於當前位置。 顯然,這兩個位置對於重複元素是不同的。

使用過濾器回調的第三個(“this array”)參數,我們可以避免關閉數組變量:

uniqueArray = a.filter(function(item, pos, self) {
    return self.indexOf(item) == pos;
})

雖然簡潔,但該算法對於大型數組(二次時間)並不是特別有效。

哈希表來拯救

function uniq(a) {
    var seen = {};
    return a.filter(function(item) {
        return seen.hasOwnProperty(item) ? false : (seen[item] = true);
    });
}

這是通常的做法。 這個想法是把每個元素放在散列表中,然後立即檢查它的存在。 這給了我們線性時間,但至少有兩個缺點:

  • 由於哈希鍵只能是Javascript中的字符串,因此此代碼不會區分數字和“數字字符串”。 也就是說, uniq([1,"1"])只會返回[1]
  • 出於同樣的原因,所有的對像都被認為是相同的: uniq([{foo:1},{foo:2}])將只返回[{foo:1}]

也就是說,如果你的數組只包含原語,並且你不關心類型(例如它總是數字),這個解決方案是最優的。

來自兩個世界的最好

通用的解決方案結合了兩種方法:它使用基元的哈希查找和對象的線性搜索。

function uniq(a) {
    var prims = {"boolean":{}, "number":{}, "string":{}}, objs = [];

    return a.filter(function(item) {
        var type = typeof item;
        if(type in prims)
            return prims[type].hasOwnProperty(item) ? false : (prims[type][item] = true);
        else
            return objs.indexOf(item) >= 0 ? false : objs.push(item);
    });
}

排序| uniq的

另一種選擇是先對數組進行排序,然後刪除與前一個元素相同的元素:

function uniq(a) {
    return a.sort().filter(function(item, pos, ary) {
        return !pos || item != ary[pos - 1];
    })
}

再次,這不適用於對象(因為所有對像都是相同的)。 此外,我們默默地改變原始數組作為副作用 - 不好! 但是,如果您的輸入已經排序,這是要走的路(只是從上面刪除sort )。

獨一無二...

有時需要基於除了相等之外的某些標準來唯一化列表,例如過濾掉不同的對象,但共享某些屬性。 這可以通過傳遞回調來優雅地完成。 這個“關鍵”回調應用於每個元素,並且具有相同“關鍵字”的元素被移除。 由於key預期會返回一個原語,因此散列表在這裡可以正常工作:

function uniqBy(a, key) {
    var seen = {};
    return a.filter(function(item) {
        var k = key(item);
        return seen.hasOwnProperty(k) ? false : (seen[k] = true);
    })
}

一個特別有用的key()JSON.stringify ,它將刪除物理上不同的對象,但“看起來”是一樣的:

a = [[1,2,3], [4,5,6], [1,2,3]]
b = uniqBy(a, JSON.stringify)
console.log(b) // [[1,2,3], [4,5,6]]

如果key不是原始的,則必須求助於線性搜索:

function uniqBy(a, key) {
    var index = [];
    return a.filter(function (item) {
        var k = key(item);
        return index.indexOf(k) >= 0 ? false : index.push(k);
    });
}

或者使用ES6中的Set對象:

function uniqBy(a, key) {
    var seen = new Set();
    return a.filter(item => {
        var k = key(item);
        return seen.has(k) ? false : seen.add(k);
    });
}

(有些人喜歡!seen.has(k) && seen.add(k)而不是seen.has(k) ? false : seen.add(k) )。

圖書館

underscoreLo-Dash提供了uniq方法。 他們的算法與上面的第一個片段基本相似,歸結為:

var result = [];
a.forEach(function(item) {
     if(result.indexOf(item) < 0) {
         result.push(item);
     }
});

這是二次的,但是還有很多其他的好處,比如包裝本地indexOf ,通過鍵(用他們的說法iteratee )來優化鍵值的能力以及對已經排序的數組進行優化。

如果你使用的是jQuery,如果沒有一美元就無法忍受任何東西,它就像這樣:

  $.uniqArray = function(a) {
        return $.grep(a, function(item, pos) {
            return $.inArray(item, a) === pos;
        });
  }

這也是第一個片段的變體。

性能

JavaScript中的函數調用非常昂貴,因此上述解決方案儘管簡潔明了,但效率並不高。 為了獲得最佳性能,請使用循環替換filter並擺脫其他函數調用:

function uniq_fast(a) {
    var seen = {};
    var out = [];
    var len = a.length;
    var j = 0;
    for(var i = 0; i < len; i++) {
         var item = a[i];
         if(seen[item] !== 1) {
               seen[item] = 1;
               out[j++] = item;
         }
    }
    return out;
}

這段醜陋的代碼和上面的代碼片段#3一樣, 但速度要快一點 (截至2017年, 速度只有它的兩倍--JS的核心人員做得很好!)

function uniq(a) {
    var seen = {};
    return a.filter(function(item) {
        return seen.hasOwnProperty(item) ? false : (seen[item] = true);
    });
}

function uniq_fast(a) {
    var seen = {};
    var out = [];
    var len = a.length;
    var j = 0;
    for(var i = 0; i < len; i++) {
         var item = a[i];
         if(seen[item] !== 1) {
               seen[item] = 1;
               out[j++] = item;
         }
    }
    return out;
}

/////

var r = [0,1,2,3,4,5,6,7,8,9],
    a = [],
    LEN = 1000,
    LOOPS = 1000;

while(LEN--)
    a = a.concat(r);

var d = new Date();
for(var i = 0; i < LOOPS; i++)
    uniq(a);
document.write('<br>uniq, ms/loop: ' + (new Date() - d)/LOOPS)

var d = new Date();
for(var i = 0; i < LOOPS; i++)
    uniq_fast(a);
document.write('<br>uniq_fast, ms/loop: ' + (new Date() - d)/LOOPS)

ES6

ES6提供了Set對象,這使得事情變得更容易:

function uniq(a) {
   return Array.from(new Set(a));
}

要么

let uniq = a => [...new Set(a)];

請注意,與python不同,ES6集以迭代順序進行迭代,因此此代碼保留了原始數組的順序。

但是,如果您需要一個具有獨特元素的數組,為什麼不從一開始就使用集合?

發電機

基於生成器的uniq的“懶惰”版本可以建立在相同的基礎上:

  • 從參數中取出下一個值
  • 如果已經看到,請跳過它
  • 否則,產生它並將其添加到已經看到的值的集合中

function* uniqIter(a) {
    let seen = new Set();

    for (let x of a) {
        if (!seen.has(x)) {
            seen.add(x);
            yield x;
        }
    }
}

// example:

function* randomsBelow(limit) {
    while (1)
        yield Math.floor(Math.random() * limit);
}

// note that randomsBelow is endless

count = 20;
limit = 30;

for (let r of uniqIter(randomsBelow(limit))) {
    console.log(r);
    if (--count === 0)
        break
}

// exercise for the reader: what happens if we set `limit` less than `count` and why


使用Underscore.js

這是一個具有許多操作數組的函數的庫。

這與jQuery的tux和Backbone.js的吊帶配合。

underscore

_.uniq(array, [isSorted], [iterator]) 別名: 唯一
生成數組的非重複版本,使用===測試對象相等性。 如果您事先知道數組已排序,則傳遞true以執行isSorted將運行更快的算法。 如果您想基於轉換計算唯一項目,請傳遞迭代器函數。

Example

var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];

alert(_.uniq(names, false));

注意: Lo-DashUnderscore.js競爭者)也提供了可比的lodash.com/docs#uniq實現。


https://jsfiddle.net/2w0k5tz8/

function remove_duplicates(array_){
    var ret_array = new Array();
    for (var a = array_.length - 1; a >= 0; a--) {
        for (var b = array_.length - 1; b >= 0; b--) {
            if(array_[a] == array_[b] && a != b){
                delete array_[b];
            }
        };
        if(array_[a] != undefined)
            ret_array.push(array_[a]);
    };
    return ret_array;
}

console.log(remove_duplicates(Array(1,1,1,2,2,2,3,3,3)));

Loop through, remove duplicates, and create a clone array place holder because the array index will not be updated.

Loop backward for better performance ( your loop wont need to keep checking the length of your array)


香草JS:使用像一個集合的對象刪除重複

您始終可以嘗試將其放入對像中,然後遍歷其中的鍵:

function remove_duplicates(arr) {
    var obj = {};
    var ret_arr = [];
    for (var i = 0; i < arr.length; i++) {
        obj[arr[i]] = true;
    }
    for (var key in obj) {
        ret_arr.push(key);
    }
    return ret_arr;
}

香草JS:通過跟踪已經看到的值刪除重複項(順序安全)

或者,對於訂單安全版本,請使用對象來存儲先前看到的所有值,並在添加到數組之前檢查值。

function remove_duplicates_safe(arr) {
    var seen = {};
    var ret_arr = [];
    for (var i = 0; i < arr.length; i++) {
        if (!(arr[i] in seen)) {
            ret_arr.push(arr[i]);
            seen[arr[i]] = true;
        }
    }
    return ret_arr;

}

ECMAScript 6:使用新的Set數據結構(訂單安全)

ECMAScript 6添加了新的Set Data-Structure,它可以讓你存儲任何類型的值。 Set.values以插入順序返回元素。

function remove_duplicates_es6(arr) {
    let s = new Set(arr);
    let it = s.values();
    return Array.from(it);
}

用法示例:

a = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];

b = remove_duplicates(a);
// b:
// ["Adam", "Carl", "Jenny", "Matt", "Mike", "Nancy"]

c = remove_duplicates_safe(a);
// c:
// ["Mike", "Matt", "Nancy", "Adam", "Jenny", "Carl"]

d = remove_duplicates_es6(a);
// d:
// ["Mike", "Matt", "Nancy", "Adam", "Jenny", "Carl"]


一條線:

let names = ['Mike','Matt','Nancy','Adam','Jenny','Nancy','Carl', 'Nancy'];
let dup = [...new Set(names)];
console.log(dup);

一種簡單而有效的技術是將filter方法與過濾function(value, index){ return this.indexOf(value) == index }

代碼示例:

var data = [2,3,4,5,5,4];
var filter = function(value, index){ return this.indexOf(value) == index };
var filteredData = data.filter(filter, data );

document.body.innerHTML = '<pre>' + JSON.stringify(filteredData, null, '\t') +  '</pre>';

另見這個小提琴


你可以簡單地用JavaScript實現,在filter方法的第二個索引參數的幫助下:

var a = [2,3,4,5,5,4];
a.filter(function(value, index){ return a.indexOf(value) == index });

或簡而言之

a.filter((v,i) => a.indexOf(v) == i)

使用jQuery快速和骯髒:

var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
var uniqueNames = [];
$.each(names, function(i, el){
    if($.inArray(el, uniqueNames) === -1) uniqueNames.push(el);
});

使用數組過濾器和indexOf函數的單行版本:

arr = arr.filter (function (value, index, array) { 
    return array.indexOf (value) == index;
});

厭倦了用for-loops或jQuery看到所有不好的例子。 現在,Javascript有著完美的工具:排序,映射和縮減。

Uniq在保持現有訂單的同時減少

var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];

var uniq = names.reduce(function(a,b){
    if (a.indexOf(b) < 0 ) a.push(b);
    return a;
  },[]);

console.log(uniq, names) // [ 'Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Carl' ]

// one liner
return names.reduce(function(a,b){if(a.indexOf(b)<0)a.push(b);return a;},[]);

更快uniq與排序

有可能更快的方法,但這個是相當不錯的。

var uniq = names.slice() // slice makes copy of array before sorting it
  .sort(function(a,b){
    return a > b;
  })
  .reduce(function(a,b){
    if (a.slice(-1)[0] !== b) a.push(b); // slice(-1)[0] means last item in array without removing it (like .pop())
    return a;
  },[]); // this empty array becomes the starting value for a

// one liner
return names.slice().sort(function(a,b){return a > b}).reduce(function(a,b){if (a.slice(-1)[0] !== b) a.push(b);return a;},[]);

2015年更新:ES6版本:

在ES6中,您有Sets和Spread,這使得它非常容易和高效地刪除所有重複項:

var uniq = [ ...new Set(names) ]; // [ 'Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Carl' ]

根據發生情況排序:

有人詢問根據有多少獨特名稱對結果進行排序:

var names = ['Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Nancy', 'Carl']

var uniq = names
  .map((name) => {
    return {count: 1, name: name}
  })
  .reduce((a, b) => {
    a[b.name] = (a[b.name] || 0) + b.count
    return a
  }, {})

var sorted = Object.keys(uniq).sort((a, b) => uniq[a] < uniq[b])

console.log(sorted)

在ECMAScript 6(又名ECMAScript 2015)中,可以使用Set來過濾重複項。 然後可以使用擴展運算符將其轉換回數組。

var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"],
    unique = [...new Set(names)];

對thg435使用自定義比較器的出色答案稍作修改:

function contains(array, obj) {
    for (var i = 0; i < array.length; i++) {
        if (isEqual(array[i], obj)) return true;
    }
    return false;
}
//comparator
function isEqual(obj1, obj2) {
    if (obj1.name == obj2.name) return true;
    return false;
}
function removeDuplicates(ary) {
    var arr = [];
    return ary.filter(function(x) {
        return !contains(arr, x) && arr.push(x);
    });
}

所以選項是:

let a = [11,22,11,22];
let b = []


b = [ ...new Set(a) ];     
// b = [11, 22]

b = Array.from( new Set(a))   
// b = [11, 22]

b = a.filter((val,i)=>{
  return a.indexOf(val)==i
})                        
// b = [11, 22]

最上面的答案有O(n)的複雜性,但這可以通過使用一個對像作為哈希來完成,只需O(n)

function getDistinctArray(arr) {
    var dups = {};
    return arr.filter(function(el) {
        var hash = el.valueOf();
        var isDup = dups[hash];
        dups[hash] = true;
        return !isDup;
    });
}

這將適用於字符串,數字和日期。 如果您的數組包含複雜的對象(即,它們必須與===進行比較),則上述解決方案將不起作用。 您可以通過在對像上設置一個標誌來獲得對象的O(n)實現:

function getDistinctObjArray(arr) {
    var distinctArr = arr.filter(function(el) {
        var isDup = el.inArray;
        el.inArray = true;
        return !isDup;
    });
    distinctArr.forEach(function(el) {
        delete el.inArray;
    });
    return distinctArr;
}

這只是另一個解決方案,但與其他解決方案不同。

function diffArray(arr1, arr2) {
  var newArr = arr1.concat(arr2);
  newArr.sort();
  var finalArr = [];
  for(var i = 0;i<newArr.length;i++) {
   if(!(newArr[i] === newArr[i+1] || newArr[i] === newArr[i-1])) {
     finalArr.push(newArr[i]);
   } 
  }
  return finalArr;
}

這是對這個問題的簡單回答。

var names = ["Alex","Tony","James","Suzane", "Marie", "Laurence", "Alex", "Suzane", "Marie", "Marie", "James", "Tony", "Alex"];
var uniqueNames = [];

    for(var i in names){
        if(uniqueNames.indexOf(names[i]) === -1){
            uniqueNames.push(names[i]);
        }
    }

這對於理解和在任何地方(甚至在PhotoshopScript中)代碼都是非常簡單的。核實!

var peoplenames = new Array("Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl");

peoplenames = unique(peoplenames);
alert(peoplenames);

function unique(array){
    var len = array.length;
    for(var i = 0; i < len; i++) for(var j = i + 1; j < len; j++) 
        if(array[j] == array[i]){
            array.splice(j,1);
            j--;
            len--;
        }
    return array;
}

//*result* peoplenames == ["Mike","Matt","Nancy","Adam","Jenny","Carl"]

$(document).ready(function() {

    var arr1=["dog","dog","fish","cat","cat","fish","apple","orange"]

    var arr2=["cat","fish","mango","apple"]

    var uniquevalue=[];
    var seconduniquevalue=[];
    var finalarray=[];

    $.each(arr1,function(key,value){

       if($.inArray (value,uniquevalue) === -1)
       {
           uniquevalue.push(value)

       }

    });

     $.each(arr2,function(key,value){

       if($.inArray (value,seconduniquevalue) === -1)
       {
           seconduniquevalue.push(value)

       }

    });

    $.each(uniquevalue,function(ikey,ivalue){

        $.each(seconduniquevalue,function(ukey,uvalue){

            if( ivalue == uvalue)

            {
                finalarray.push(ivalue);
            }   

        });

    });
    alert(finalarray);
});




duplicates