Лучший способ перебирать массив и разбирать каждый элемент на несколько структур данных

#javascript #arrays

#javascript #массивы

Вопрос:

У меня есть массив из ~ 11 000 словарей JavaScript, каждый из которых представляет 1 строку в файле Excel.

Я хочу перебрать этот массив и преобразовать каждый элемент в новую структуру данных. Например, у меня может быть функция, которая будет считаться за {"foo": true} или что-то в этомроде.

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

Пример. В настоящее время я выполняю один цикл и преобразую каждый элемент в глобальную переменную

 const arr = [...];  // array of ~11,000 dictionaries

// example parsing function
let count = 0;
function countFoos(el) {
  if (el["foo"] === true) count  ;
}

let count2 = 0;
function countBars(el) {
  if (el["bar"] === false) count2  ;
}

arr.forEach(el => {
  countFoos(el);
  countBars(el);
});
  

Но было бы лучше сделать это таким образом?

 class Parse {
  constructor(arr) {
    this.arr = arr;
    this.count = 0;
    this.count2 = 0;
  }

  countFoos() {
    this.arr.forEach((el) => {
      if (el["foo"] === true) this.count  ;
    });
  }

  countBars() {
    this.arr.forEach((el) => {
      if (el["bar"] === false) this.count2  ;
    });
  }
}

const arr = [...]; // array of ~11,000 dictionaries
let x = Parse();
x.countFoos();
x.countBars();
  

РЕДАКТИРОВАТЬ: Мне следовало уточнить заранее, приведенные выше примеры — это просто очень упрощенные примеры производственного кода. Для каждого элемента выполняется примерно 20 «функций синтаксического анализа», причем каждая из соответствующих ему глобальных переменных представляет собой большие словари или массивы.

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

1. Вы могли бы использовать reduce для этого, что потребовало бы всего одного прохода

Ответ №1:

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

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

Ответ №2:

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

Если вы считаете, что использование классов более читабельно, вы могли бы просто записать это как один метод в классе.

 class Parse {
  constructor(arr) {
    this.arr = arr;
    this.count = 0;
    this.count2 = 0;
  }

  count() {
    this.arr.forEach((el) => {
      countFoos(el), countBars(el);
    });
  }
  countFoos(el){
    if(el.foo === true) this.count1  ;
  }
  countBars() {
    if(el.bar === false) this.count2  ;
  }
}

  

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

1. Да, я беспокоюсь о производительности, потому что она масштабируется по мере того, как мы добавляем больше данных в массив / функции для разбора этих данных. Однако я обеспокоен тем, что текущая реализация не очень удобочитаема.

2. @urvianoob обновил мой ответ.

Ответ №3:

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

 function count(arr) {
    return arr.reduce(([fooCount, barCount], next) => {
        if (next.foo === true) {
            fooCount = fooCount   1
        }

        if (next.bar === false) {
            barCount = barCount   1
        }

        return [fooCount, barCount]
    }, [0, 0]);
}

const [fooCount, barCount] = count(...);
  

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

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

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

Ответ №4:

Ограничение количества циклов — ваш лучший вариант, поскольку это требует меньше накладных расходов.

Также есть идея использовать foreach для выполнения обработки с помощью операторов if и использовать один объект counter для хранения всех значений, чтобы они что-то значили и на них можно было легко ссылаться позже.

 const arr = [
   {"foo" : true,"bar" : false},{"bar" : true,"foo" : false}
];

let counters = {};

function inc(field) {
  if (counters[field] == undefined) {
    counters[field] = 0;
  }
  counters[field]  ;
}

arr.forEach(el => {
  if (el["foo"] === true) {
    inc("foo");
  } 
if (el["bar"] === true) {
    inc("bar");
  }
});

console.log(counters);