Найдите повторяющиеся имена в массиве разных файлов

#javascript #reactjs #loops #if-statement #recursion

Вопрос:

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

До сих пор это мой код, и, конечно, у меня проблема с моей условной проверкой, может ли кто-нибудь увидеть, что я делаю не так?

 filesForStorage = [
{id: 12323, name: 'name', ...},
{id: 3123, name: 'abc', ...},
{id: 3213, name: 'name', ...},
...
]

    filesForStorage.map((image, index) => {
          for (let i = 0; i < filesForStorage.length; i  ) {
            for (let j = 0; j < filesForStorage.length; j  ) {
              if (
                filesForStorage[i].name.split(".", 1) ===.   //.split('.', 1) is to not keep in consideration the file extension
                filesForStorage[j].name.split(".", 1)
              ) {
                console.log(
                  "----FILES HAVE THE SAME NAME "  
                    filesForStorage[i]  
                    " "  
                    filesForStorage[j]
                );
              }
            }
          }
 

Комментарии:

1. Не могли бы вы поделиться демонстрационными данными для хранилища файлов? Фрагмент был бы замечательным.

2. Почему вы запускаете 2 for цикла Array.map ?

3. уверен, массив и файлы следующим образом: массив (10) 0 файл {идентификатор: 0.6385802192553822, анонс: «BLOB-объектов: например, localhost:3000/c857aaa7-51dd-4d8a-в209-810b9eaf9d34 «, уникальный идентификатор: «8Am0GOPEwATyd0ZkSHlG», имя: «background1.jpeg», lastModified: 1624555546000, …} 1 файл {живут: True, идентификатор: 0.6403926850353915, анонс: «BLOB-объектов: например, localhost:3000/e6db45de-cd66-408e-8c55-ac9a9968d504 «, уникальный идентификатор: «6hPqArZp1nNqruDIbh74», название: «image.gif», …} 2 файла {идентификатор: 0.5735947653890782, анонс: «BLOB-объектов: например, localhost:3000/697954be-50ee-46e6-ba38-8d6be54e7a9d «, название: «фон.ПНГ», … }, …]

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

5. @Jacopo, пожалуйста, отформатируйте их и добавьте в вопрос

Ответ №1:

Использование map без возврата чего-либо делает его почти бессмысленным. Вы могли бы использовать forEach , но это одинаково бессмысленно, когда вы используете двойной цикл внутри — это означает, что вы будете зацикливаться один раз foreach (или map в вашем случае), а затем еще два раза, что приведет к ухудшению производительности.

То, что вы действительно пытаетесь сделать, это сгруппировать свои элементы по name , а затем выбрать любую группу с более чем 1 элементом

 const filesForStorage = [
{id: 12323, name: 'name'},
{id: 3123, name: 'abc'},
{id: 3213, name: 'name'}
]

const grouped = Object.values(
  filesForStorage.reduce( (a,i) => {
    a[i.name] = a[i.name] || [];
    a[i.name].push(i);
    return a;
  },{})
);

console.log(grouped.filter(x => x.length>1).flat()); 

Комментарии:

1. Твое здоровье, Джейми! Ценю ваш ответ!

2. Кроме того, могу ли я объединить(удалить) найденные файлы из исходного массива в reduce?

3. @Jacopo Те, у которых есть только один вход в систему, могут вообще grouped.filter(x => x.length == 0).flat() не нуждаться в изменении исходного массива.

4. Я бы рекомендовал использовать набор или карту вместо массива

Ответ №2:

JavaScript имеет несколько функций, которые выполняют «скрытую» итерацию.

  • Object.values будет перебирать объект пар ключ-значение и собирать все значения в массив
  • Array.prototype.reduce будет перебирать массив и выполнять вычисления для каждого элемента и, наконец, возвращать одно значение
  • Array.prototype.filter выполнит итерацию по массиву и соберет все элементы, возвращающие значение true для указанного теста
  • Array.prototype.flat будет выполнять итерацию по массиву, объединяя каждый элемент со следующим, чтобы создать новый сплющенный массив

Все эти методы являются расточительными, поскольку вы можете вычислить набор дубликатов, используя один проход по входному массиву. Кроме того, методы массива в лучшем случае обеспечивают производительность O(n) по сравнению с производительностью набора или карты O(1), что делает выбор массивов для такого рода вычислений крайне неудачным —

 function* duplicates (files) {
  const seen = new Set()
  for (const f of files) {
    if (seen.has(f.name))
      yield f
    else
      seen.add(f.name, f)
  }
}

const filesForStorage = [
  {id: 12323, name: 'foo'},
  {id: 3123, name: 'abc'},
  {id: 3213, name: 'foo'},
  {id: 4432, name: 'bar'},
  {id: 5213, name: 'qux'},
  {id: 5512, name: 'bar'},
]

for (const d of duplicates(filesForStorage))
  console.log("duplicate name found", d) 
 duplicate name found {
  "id": 3213,
  "name": "foo"
}
duplicate name found {
  "id": 5512,
  "name": "bar"
}
 

Ответ №3:

Вложенный цикл может быть очень дорогим по производительности, особенно если в вашем массиве будет много значений. Что-то подобное было бы намного лучше.

 filesForStorage = [
  { id: 12323, name: 'name' },
  { id: 3123, name: 'abc' },
  { id: 3213, name: 'name' },
  { id: 3123, name: 'abc' },
  { id: 3213, name: 'name' },
  { id: 3123, name: 'random' },
  { id: 3213, name: 'nothing' },
]

function sameName() {
  let checkerObj = {};
  let newArray = [];

  filesForStorage.forEach(file => {
   checkerObj[file.name] = (checkerObj[file.name] || 0)   1;
  });

  Object.entries(checkerObj).forEach(([key, value]) => {
    if (value > 1) {
      newArray.push(key);
    }
  });

  console.log(newArray);

}

sameName();