Получить все уникальные значения в массиве JavaScript (удалить дубликаты)

У меня есть массив чисел, которые я должен убедиться, что они уникальны. Я нашел фрагмент кода ниже в интернете, и он прекрасно работает, пока в массиве нет нуля. Я нашел этот другой скрипт здесь на SO, который выглядит почти так же, как и он, но он не дает сбоя.

Таким образом, ради того, чтобы помочь мне учиться, может ли кто-нибудь помочь мне определить, в чем проблема с прототипом скрипта?

Array.prototype.getUnique = function() {
 var o = {}, a = [], i, e;
 for (i = 0; e = this[i]; i++) {o[e] = 1};
 for (e in o) {a.push (e)};
 return a;
}

Больше ответов от дублирующего вопроса:

Подобный вопрос:

140 ответов

Самый простой способ - преобразовать значения в строки для фильтрации значений вложенных объектов.

const uniq = (arg = []) => {
  const stringifyedArg = arg.map(value => JSON.stringify(value))
  return arg.filter((value, index, self) => {
    if (typeof value === 'object')
      return stringifyedArg.indexOf(JSON.stringify(value)) === index
    return self.indexOf(value) === index
  })
}

    console.log(uniq([21, 'twenty one', 21])) // [21, 'twenty one']
    console.log(uniq([{ a: 21 }, { a: 'twenty one' }, { a: 21 }])) // [{a: 21}, {a: 'twenty one'}]

Вам вообще не нужен.indexOf(); вы можете сделать это O(n):

function SelectDistinct(array) {
    var seenIt = {};

    return array.filter(function (val) {
        if (seenIt[val]) 
            return false;
        return seenIt[val] = true;
    });
}

var hasDuplicates = [1,2,3,4,5,5,6,7,7];
console.log(SelectDistinct(hasDuplicates)) //[1,2,3,4,5,6,7]

Если вы не хотите использовать.filter():

function SelectDistinct(array) {
    var seenIt = {};
    var distinct = [];

    for (var i in array) {
        if (!seenIt[array[i]]) {
            seenIt[array[i]] = true;
            distinct.push(array[i]);
        }
    }

    return distinct;
}

Версия, которая принимает селектор, должна быть довольно быстрой и лаконичной:

function unique(xs, f) {
  var seen = {};
  return xs.filter(function(x) {
    var fx = (f && f(x)) || x;
    return !seen[fx] && (seen[fx] = 1);
  });
}

Array .forEach для обхода каждого элемента через массив и проверки условия if, если новый массив уже содержит элемент. Надеюсь это поможет!!

    var arr = [1, 2, 2, 3, 4, 5, 6, 7, 7, 7, 7, 8, 9, 4, 3, 3, 5];
    let arr1 = [];
    arr.forEach(elem => {
        if (!arr1.includes(elem)) {
            arr1.push(elem);
        }
    });
    console.log(arr1);

Многие люди уже упоминали об использовании...

[...new Set(arr)];

И это отличное решение, но я предпочитаю решение, которое работает с .filter. На мой взгляд, фильтр - более естественный способ получить уникальные значения. Вы эффективно удаляете дубликаты, а удаление элементов из массива - это именно то, для чего предназначен фильтр. Это также позволяет вам цепляться за.map, .reduce и другие .filterзвонки. Я придумал это решение...

const unique = () => {
  let cache;  
  return (elem, index, array) => {
    if (!cache) cache = new Set(array);
    return cache.delete(elem);
  };
};

myArray.filter(unique());

Предостережение в том, что вам нужно закрытие, но я думаю, что это достойный компромисс. С точки зрения производительности, это более производительно, чем другие решения, которые я видел, которые используют.filter, но хуже, чем [...new Set(arr)].

См. Также мой пакет github youneek

Это функция ES6, которая удаляет дубликаты из массива объектов, фильтруя по указанному свойству объекта

function dedupe(arr = [], fnCheck = _ => _) {
  const set = new Set();
  let len = arr.length;

  for (let i = 0; i < len; i++) {
    const primitive = fnCheck(arr[i]);
    if (set.has(primitive)) {
      // duplicate, cut it
      arr.splice(i, 1);
      i--;
      len--;
    } else {
      // new item, add it
      set.add(primitive);
    }
  }

  return arr;
}

const test = [
    {video:{slug: "a"}},
    {video:{slug: "a"}},
    {video:{slug: "b"}},
    {video:{slug: "c"}},
    {video:{slug: "c"}}
]
console.log(dedupe(test, x => x.video.slug));

// [{video:{slug: "a"}}, {video:{slug: "b"}}, {video:{slug: "c"}}]

Еще одно решение для кучи.

Недавно мне нужно было сделать отсортированный список уникальным, и я сделал это с помощью фильтра, который отслеживает предыдущий элемент в объекте, подобном этому:

uniqueArray = sortedArray.filter(function(e) { 
    if(e==this.last) 
      return false; 
    this.last=e; return true;  
  },{last:null});

Это один из подходов с использованием карты сокращения.

const arr = [{id: '1'},{id: '4'},{id: '2'},{id: '1'},{id: '3'},{id: '1'},{id: '1'},{id: '5'}]

let uniqueArr = arr.reduce((arr, item) => {
  const uniq = arr.filter(i => i.id !== item.id)
    return [...uniq, item]
  }, [])

Я знаю, что на этот вопрос уже ответили до смерти... но... никто не упомянул реализацию linq на javascript. Тогда .distinct() метод может быть использован - и это делает код очень легко читаемым.

var Linq = require('linq-es2015');
var distinctValues =  Linq.asEnumerable(testValues)
            .Select(x)
            .distinct()
            .toArray();

var testValues = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 1];

var distinctValues = Enumerable.asEnumerable(testValues)
  .distinct()
  .toArray();

console.log(distinctValues);
<script src="https://npmcdn.com/linq-es5/dist/linq.js"></script>

Когда вы говорите уникальные значения, для меня это означает значения, которые появляются один раз и только один раз в наборе данных.

Следующее фильтрует массив значений, проверяя, что первый и последний индексы данного значения равны. Если индекс равен, это означает, что значение должно появиться только один раз.

var values = [1, 2, 3, 4, 5, 2, 4, 6, 2, 1, 5];

var unique = values.filter(function(value) {
  return values.indexOf(value) === values.lastIndexOf(value);
});

console.log(unique); // [3, 6]

Основываясь на отзывах, которые я неправильно понял, вот альтернативный подход, который возвращает уникальные, не повторяющиеся значения из массива значений.

var values = [1, 2, 3, 4, 5, 2, 4, 6, 2, 1, 5];
var unique = values.reduce(function(unique, value) {
  return unique.indexOf(value) === -1 ? unique.concat([value]) : unique;
}, []);

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

Я использую этот экстремально простой, и я почти уверен, что он совместим со всеми браузерами, но в современных браузерах он устарел:

Для массива строк:

function removeDuplicatesFromArray(arr) {
  const unique = {};
  arr.forEach((word) => {
    unique[word] = 1; // it doesn't really matter what goes here
  });
  return Object.keys(unique);
}
var numbers = [1,1,2,3,4,4];

function unique(dupArray) {
    return  dupArray.reduce(function (previous, num){

        if (previous.find(function(item){
            return item == num;
        })) {
            return previous;
        } else {
            previous.push(num);
            return previous;
        }
    }, [])
}

var check = unique(numbers);
console.log(check);

Для массива кортежей я добавляю вещи в карту и позволяю ей делать свою работу. При таком подходе вы должны помнить о ключе, который хотите использовать:

      const arrayOfArraysWithDuplicates = [
    [1, 'AB'],
    [2, 'CD'],
    [3, 'EF'],
    [1, 'AB'],
    [2, 'CD'],
    [3, 'EF'],
    [3, 'GH'],
]

const uniqueByFirstValue = new Map();
const uniqueBySecondValue = new Map();

arrayOfArraysWithDuplicates.forEach((item) => {
    uniqueByFirstValue.set(item[0], item[1]);
    uniqueBySecondValue.set(item[1], item[0]);
});

let uniqueList = Array.from( uniqueByFirstValue, ( [ value, name ] ) => ( [value, name] ) );

console.log('Unique by first value:');
console.log(uniqueList);

uniqueList = Array.from( uniqueBySecondValue, ( [ value, name ] ) => ( [value, name] ) );

console.log('Unique by second value:');
console.log(uniqueList);

Выход:

      Unique by first value:
[ [ 1, 'AB' ], [ 2, 'CD' ], [ 3, 'GH' ] ]

Unique by second value:
[ [ 'AB', 1 ], [ 'CD', 2 ], [ 'EF', 3 ], [ 'GH', 3 ] ]

Всегда помните, встроенные методы просты в использовании. Но имейте в виду, что они имеют сложность.

Базовая логика лучше всего. Нет скрытой сложности.

      let list = [1, 1, 2, 100, 2] // your array
let check = {}
list = list.filter(item => {
    if(!check[item]) {
        check[item] = true
        return true;
    }
})

или используйте, let check = [] если вам нужно в будущем перейти к отмеченным элементам (хотя пустая трата памяти)

Создание массива уникальных массивов с использованием поля [2] в качестве идентификатора:

[ [ '497', 'Q0', 'WTX091-B06-138', '0', '1.000000000', 'GROUP001' ],
  [ '497', 'Q0', 'WTX091-B09-92', '1', '0.866899288', 'GROUP001' ],
  [ '497', 'Q0', 'WTX091-B09-92', '2', '0.846036819', 'GROUP001' ],
  [ '497', 'Q0', 'WTX091-B09-57', '3', '0.835025326', 'GROUP001' ],
  [ '497', 'Q0', 'WTX091-B43-79', '4', '0.765068215', 'GROUP001' ],
  [ '497', 'Q0', 'WTX091-B43-56', '5', '0.764211464', 'GROUP001' ],
  [ '497', 'Q0', 'WTX091-B44-448', '6', '0.761701704', 'GROUP001' ],
  [ '497', 'Q0', 'WTX091-B44-12', '7', '0.761701704', 'GROUP001' ],
  [ '497', 'Q0', 'WTX091-B49-128', '8', '0.747434800', 'GROUP001' ],
  [ '497', 'Q0', 'WTX091-B18-17', '9', '0.746724770', 'GROUP001' ],
  [ '497', 'Q0', 'WTX091-B19-374', '10', '0.733379549', 'GROUP001' ],
  [ '497', 'Q0', 'WTX091-B19-344', '11', '0.731421782', 'GROUP001' ],
  [ '497', 'Q0', 'WTX091-B09-92', '12', '0.726450470', 'GROUP001' ],
  [ '497', 'Q0', 'WTX091-B19-174', '13', '0.712757036', 'GROUP001' ] ]
    .filter((val1, idx1, arr) => !!~val1.indexOf(val1[2]) && 
    !(arr.filter((val2, idx2) => !!~val2.indexOf(val1[2]) && 
idx2 < idx1).length));

Уже есть куча отличных ответов. Вот мой подход.

      var removeDuplicates = function(nums) {
    let filteredArr = [];
    nums.forEach((item) => {
        if(!filteredArr.includes(item)) {
            filteredArr.push(item);
        }
    })

  return filteredArr;
}

Старый способ с двумя петлями.

      let a = ["Messi", 23, false, 11, 17, true, 23, "Messi", "Sachin", "2023", true, "Sachin"];

let b = [];
    for (let i in a) {
        let found = false;
        for (let j in b) {
            if (a[i] === b[j]) {
                found = true;
                break;
            }
        }
        if (found === false) {
            b.push(a[i]);
        }
    }

console.log(b); //['Messi', 23, false, 11, 17, true, 'Sachin', '2023']

ES2016 .includes() Один метод Простой ответ:

      var arr = [1,5,2,4,1,6]
function getOrigs(arr) {
  let unique = []
  arr && arr.forEach(number => {
    !unique.includes(number) && unique.push(number)
    if (number === arr[arr.length - 1]) {
      console.log('unique: ', unique)
    }
  })
}
getOrigs(arr)

Используйте это вместо этого:

  • более поздняя версия ES
  • Простой вопрос не должен использовать несколько расширенных методов JS, а push(), length() и forEach() являются общими.
  • Более легкая читаемость с использованием замыкания
  • Кажется, лучше по памяти, сборке мусора и производительности, чем другие
  • Меньше строк кода: если вы разделите строки в зависимости от того, где заканчивается строка, вам понадобится только одна строка логики (так что вы можете вызывать или рефакторить этот однострочный код, как хотите):
      var arr = [1,5,2,4,1,6];
function getOrigs(arr) {let unique = []; 
  arr && arr.forEach(number => !unique.includes(number) && unique.push(number) && ((number === arr[arr.length - 1]) && console.log('unique: ', unique)))};
getOrigs(arr);

Вы можете просто использовать встроенную функцию Array.prototype.filter()

      array.filter((x, y) => array.indexOf(x) == y);

Я хотел удалить дубликаты из массива объектов. Дубликаты имели одинаковые идентификаторы. Вот что я сделал.

      // prev data
const prev = [
  {
    id: 1,
    name: "foo",
  },
  {
    id: 2,
    name: "baz",
  },
  {
    id: 1,
    name: "foo",
  },
];

// method:
// Step 1: put them in an object with the id as the key. Value of same id would get overriden.
// Step 2: get all the values.

const tempObj = {};
prev.forEach((n) => (tempObj[n.id] = n));
const next = Object.values(tempObj);

// result
[
  {
    id: 1,
    name: "foo",
  },
  {
    id: 2,
    name: "baz",
  }
];

Попробуйте сделать это:

Это перебирает массив, проверяет, является ли первый найденный результат той же записи в массиве текущим индексом, и если да, то позволяет ему быть в массиве.

Иногда мне нужно получить уникальные вхождения из массива объектов. Lodash кажется хорошим помощником, но я не думаю, что фильтрация массива оправдывает добавление зависимости в проект.

Давайте предположим, что сравнение двух объектов представляет собой сравнение свойства, например, идентификатора.

const a = [{id: 3}, {id: 4}, {id: 3}, {id: 5}, {id: 5}, {id: 5}];

Так как мы все любим отрывки из одной строки, вот как это можно сделать:

a.reduce((acc, curr) => acc.find(e => e.id === curr.id) ? acc : [...acc, curr], [])

   var elems = ['f', 'a','b','f', 'c','d','e','f','c', 'n', 'n'];

    elems.sort();

    elems.forEach(function (value, index, arr){

        let first_index = arr.indexOf(value);
        let last_index = arr.lastIndexOf(value);

         if(first_index === last_index){

         console.log('unique items in array ' + value);

         }else{

         console.log('Duplicate item in array ' + value);             

         }

    });

Однострочный код даст уникальные значения. Распространение оператора с новым Set.

let nos = [1, 2, 3, 4, 5, 6, 2, 4, 5, 6];
let uniqueNos = [...new Set(nos)];
console.log(uniqueNos); //will print 1,2,3,4,5,6

Это решение должно быть очень быстрым и будет работать во многих случаях.

  1. Преобразовать элементы индексированного массива в ключи объекта
  2. Используйте функцию Object.keys

    var indexArray = ["hi","welcome","welcome",1,-9];
    var keyArray = {};
    indexArray.forEach(function(item){ keyArray[item]=null; });
    var uniqueArray = Object.keys(keyArray);
    

Простой

Ответ Object выше, кажется, не работает для меня в моем случае использования с Objects.

Я изменил это следующим образом:

var j = {};

this.forEach( function(v) {
   var typ = typeof v;
   var v = (typ === 'object') ? JSON.stringify(v) : v;

   j[v + '::' + typ] = v;
});

return Object.keys(j).map(function(v){
  if ( v.indexOf('::object') > -1 ) {
    return JSON.parse(j[v]);
  }

  return j[v];
});

Похоже, теперь это работает правильно для объектов, массивов, массивов со смешанными значениями, логических значений и т. Д.

У меня есть простой пример, где мы можем удалить объекты из массива с повторным идентификатором в объектах,

  let data = new Array({id: 1},{id: 2},{id: 3},{id: 1},{id: 3});
  let unique = [];
  let tempArr = [];
  console.log('before', data);
  data.forEach((value, index) => {
    if (unique.indexOf(value.id) === -1) {
      unique.push(value.id);
    } else {
      tempArr.push(index);    
    }
  });
  tempArr.reverse();
  tempArr.forEach(ele => {
    data.splice(ele, 1);
  });
  console.log(data);

С моей стороны это было самое простое решение

Другие вопросы по тегам