Как эффективно построить новый массив объектов, используя уникальные значения из массивов дочерних элементов внутри массива родительских объектов - PullRequest
0 голосов
/ 22 января 2020

Нужно взять объекты вроде этого:

[ { "first": 
    { "children" : [{ "name": "abc", "detail":"123"},
                  { "name": "def", "detail":"456"}
                 ]
    }},
  { "second": 
    { "children" : [{ "name": "ghi", "detail":"123"},
                  { "name": "jkl", "detail":"456"}
                 ]
    }},
  { "third": 
    { "children" : [{ "name": "mno", "detail":"123"},
                  { "name": "pqr", "detail":"456"}
                 ]
    }},
  { "fourth": 
    { "children" : [{ "name": "stu", "detail":"123"},
                  { "name": "vwx", "detail":"456"}
                 ]
    }},
  { "fifth": 
    { "children" : [{ "name": "yz", "detail":"123"},
                  { "name": "abc", "detail":"456"}
                 ]
    }},
  { "sixth": 
    { "children" : [{ "name": "def", "detail":"123"},
                  { "name": "ghi", "detail":"456"}
                 ]
    }}
]

, а затем создать плоский массив уникальных значений (опций для выбора) из поля имени дочерних элементов, которое выглядит следующим образом:

[{"value":"abc", "label":"abc"},
 {"value":"def", "label":"def"},
 {"value":"ghi", "label":"ghi"},
 {"value":"jkl", "label":"jkl"},
 {"value":"mno", "label":"mno"},
 {"value":"pqr", "label":"pqr"},
 {"value":"stu", "label":"stu"},
 {"value":"vwx", "label":"vwx"},
 {"value":"yz", "label":"yz"}
]

Приведенный ниже код работает, но, похоже, он неэффективен, потому что кажется, что он делает много проходов по массиву:

[
  ...new Set(
     [].concat.apply([], bases.map((base) => {
       if (!base.children || base.children.length === 0) return;
       return  base.children}
     )).map((child) => child.name)
  )
].map((optName) => {return {value: optName, label: optName};})

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

Ответы [ 2 ]

3 голосов
/ 22 января 2020

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

Во-вторых, создание цепочки функций прототипа массива (например, map, forEach, filter) потребует нескольких итераций в зависимости от конструкции.

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

Вот фрагмент кода (IMO) для извлечения уникальных имен из вашего массива :

let bases = [{
    children: [{
        name: "abc",
        detail: "123"
      },
      {
        name: "def",
        detail: "456"
      }
    ]
  }, {
    children: [{
        name: "abc" ,
        detail: "123"
      },
      {
        name: "xyz" ,
        detail: "456"
      }
    ]
  },
  {}
];

let output = bases
  .flatMap(b => b.children || [])
  .map(c => c.name)
  .filter((v, i, a) => a.indexOf(v) === i) // filter unique values
  .map(name => ({
    value: name,
    label: name,
  }));
  
console.log(output);

Теперь, если вы действительно хотите сделать все это за одну итерацию, это тоже возможно, но сложнее для чтения:

let bases = [{
    children: [{
        name: "abc",
        detail: "123"
      },
      {
        name: "def",
        detail: "456"
      }
    ]
  }, {
    children: [{
        name: "abc" ,
        detail: "123"
      },
      {
        name: "xyz" ,
        detail: "456"
      }
    ]
  },
  {}
];

let output = [];
let seenNames = {};
for (base of bases) {
  if (!base.children)
    continue;
  for (child of base.children) {
    let name = child.name;
    if (seenNames[name])
      continue;
    seenNames[name] = true;
    output.push({
      value: name,
      label: name,
    });
  }
}
  
console.log(output);
1 голос
/ 22 января 2020

Вы можете взять Array#flatMap для получения плоского представления данных для использования уникальных значений и сопоставления новых объектов.

var data = [{ first: { children: [{ name: "abc", detail: "123" }, { name: "def", detail: "456" }] } }, { second: { children: [{ name: "ghi", detail: "123" }, { name: "jkl", detail: "456" }] } }, { third: { children: [{ name: "mno", detail: "123" }, { name: "pqr", detail: "456" }] } }, { fourth: { children: [{ name: "stu", detail: "123" }, { name: "vwx", detail: "456" }] } }, { fifth: { children: [{ name: "yz", detail: "123" }, { name: "abc", detail: "456" }] } }, { sixth: { children: [{ name: "def", detail: "123" }, { name: "ghi", detail: "456" }] } }],
    result = Array.from(
        new Set(data
            .flatMap(Object.values)
            .flatMap(({ children }) => children.map(({ name }) => name))
        ),
        value => ({ value, label: value })
    );

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...