Преобразование данных Javascript с помощью одной итерации

#javascript

Вопрос:

У меня есть такая структура данных.

 
const data = [
  ['source1', 'target1', 1],
  ['source2', 'target2', 2],
  ['source1', 'target2', 2]
]
 

Я хочу преобразовать это в нижеприведенную структуру.

 const transformedData = ['source1', 'source2', 'target1', 'target2'];
 

Ниже показано, как я это решил

 const transformedData = [...new Set([...this.data.map(d => d[0]), ...this.data.map(d => d[1])])];
 

Есть ли какой-нибудь способ избежать 2 итераций внутри Set() ?

Ответ №1:

На самом деле, в вашем примере у вас больше, чем просто две итерации, потому что вы распределяете все элементы. С моей точки зрения, наиболее эффективный подход использует два взаимодействия (O 2n). Сначала вы зацикливаетесь на элементе в массиве и добавляете их в набор, затем вам нужно преобразовать набор обратно в массив

 // input
const data = [
  ['source1', 'target1', 1],
  ['source2', 'target2', 2],
  ['source1', 'target2', 2]
];

// store items in set to keep them unique
const result = new Set();

// iterate over items and add first and second entry to the set
data.forEach(item => {
  result.add(item[0]);
  result.add(item[1]);
});

// convert set to array
const arr = [...result]
 

Вы могли бы использовать Array.flatMap их для перебора всего за один цикл, но в результате вы получите дубликаты:

 const res = data.flatMap(item => [item[0], item[1]])

// [ 'source1', 'target1', 'source2', 'target2', 'source1', 'target2' ]
 

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

1. что, если реализовать это так? вы конвертируете в набор только один раз. javascript const data = [ ['source1', 'target1', 1], ['source2', 'target2', 2], ['source1', 'target2', 2] ]; const result = [] data.forEach(item => { result.push(item[0]); result.push(item[1]); }); const arr = [...new Set(result)]

2. Это точно то же самое, только наоборот. На самом деле, это немного менее эффективно, потому что ваш результирующий массив содержит больше элементов, которые позже будут сведены к набору.

3. Спасибо. что, если бы мы использовали indexOf() вместо set оператора?

4. То же самое, indexOf это O(n)

Ответ №2:

Вы можете map data выбрать и вернуть элемент в 0-й и 1-й позиции индекса в виде массива. Затем вы можете использовать flat() метод массива, чтобы преобразовать массив с несколькими затемнениями в одно измерение. Вы также можете использовать new Set() и распространять ( ... ) оператор, чтобы удалить дубликаты.

 const data = [
  ['source1', 'target1', 1],
  ['source2', 'target2', 2],
  ['source1', 'target2', 2]
]

let res = data.map(e=>[e[0], e[1]])

res = [...new Set(res.flat())]

console.log(res) 

Примечание: Если вам строго нужен массив в упорядоченной форме (например ['source1', 'source2', 'target1', 'target2'] ), вам нужно использовать два forEach s, один для 0-го элемента индекса, а другой для 1-го элемента индекса, и добавить их в Set .

 const data = [
  ['source1', 'target1', 1],
  ['source2', 'target2', 2],
  ['source1', 'target2', 2]
]

let set = new Set();

data.forEach(e=>{set.add(e[0]);})
data.forEach(e=>{set.add(e[1]);})

res = [...set]

console.log(res) 

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

1. Источник и цель, я дал в целом. Это может быть любая строка. Чтобы получить заказ, я думаю, сортировка не сработает.

2. @SijilSasidharan О, хорошо. Я обновил ответ. Пожалуйста, проверьте, работает ли это.

Ответ №3:

Вы можете извлечь первые 2 значения из массива и объединить их, а затем получить все уникальные значения.

 const data = [ ['source1', 'target1', 1], ['source2', 'target2', 2], ['source1', 'target2', 2]],
      result = [...new Set([...[0, 1].flatMap(i => data.map(arr => arr[i]))])];
console.log(result); 

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

1. Источник и цель, я дал в целом. Это может быть любая строка. Чтобы получить заказ, я думаю, сортировка не сработает.

2. Итак, вы хотите, чтобы сначала значение по индексу 0, а затем значение по индексу 1. Правильно? См. Обновленное решение.

Ответ №4:

Набор не заказан, и вы можете просто удалить его.

 const transformedData = data.map(a => a[0]).concat(data.map(a => a[1]))
//  or
const transformedData = [...data.map(a => a[0]), ...data.map(a => a[1])]
// or if order doesn't matter
const transformedData = data.map(a => a.slice(0, 2)).reduce((a, b) => a.concat(b), [])
 

Ответ №5:

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

 const data = [
  ['source1', 'target1', 1],
  ['source2', 'target2', 2],
  ['source1', 'target2', 2]
];

const res = [...new Set(data.reduceRight((acc, arr, i, dat) => {
  acc.unshift(arr[0]); 
  acc.push(dat[dat.length - i - 1][1]); 
  return acc;
}, []))];

console.log(res);