Jak zsumować wartości równoważnych kluczy w tablicy obiektów, gdzie może być kilka nowo wygenerowanych kluczy?

0

Pytanie

Istnieje szereg obiektów, takich jak ten, gdzie jest klucz "kategoria" i niektóre klucze "serii".

arrOne = [
    {
        "series_1": 25,
        "category": "Category 1",
        "series_2": 50
    },
    {
        "series_1": 11,
        "category": "Category 2",
        "series_2": 22
    },
    {
        "series_1": 32,
        "category": "Category 1",
        "series_2": 74
    },
    {
        "series_1": 74,
        "category": "Category 3",
        "series_2": 98
    },
    {
        "series_1": 46,
        "category": "Category 3",
        "series_2": 29
    },

]

(Należy pamiętać, że "kategoria" może być praktycznie dowolną wartością, choć prawdopodobnie będzie kilka podobnych wartości, a także kilka unikalnych wartości, na przykład, istnieje kilka obiektów z wartością "kategoria ""Kategoria 3", ale tylko 1 z wartością "kategoria ""Kategoria 2")

W takich wierszach kodu zostaną zsumowane wszystkie serie 1 dla obiektów z tej samej kategorii

        var objForAllCategories = {};
        this.arrOne.forEach(item => {
            if (objForAllCategories.hasOwnProperty(item.category))
                objForAllCategories[item.category] = objForAllCategories[item.category] + item.series_1;
            else
                objForAllCategories[item.category] = item.series_1;
        });
        for (var prop in objForAllCategories) {
            this.allCategoriesAndValues.push({ 
                category: prop, 
                series_1: objForAllCategories[prop] 
            });
        }

W ten sposób, to by doprowadziło do:

allCategoriesAndValues = [
    {
        "category": "Category 1",
        "series_1": 57       // 25 + 32 adding up series_1 from all 'Category 1' items in arrOne
    },
    {
        "category": "Category 2",
        "series_1": 11      // only 1 'Category 2' from arrOne
    },
    {
        "category": "Category 3",
        "series_1": 120     // 74 + 46 adding up series_1 from all 'Category 3' items in arrOne
    }
]

Jednak chciałbym mieć możliwość dodawania nie tylko серии_1, ale i wszystkie inne elementy.

W tym przykładzie jako klucze są używane tylko kategorii i серии_1 i серии_2. Niemniej jednak, mogą być:

  1. серии_3
  2. серии_4
  3. seria 5
  4. seria 6
  5. seria 7
  6. itp..

Jak mogę wziąć pod uwagę wszystkie potencjalne serii x?

Przewidywany wynik:

allCategoriesAndValues = [
    {
        "category": "Category 1",
        "series_1": 57,
        "series_2": 124,
        ..... if 'series_3', 'series_4' etc. existed, it would be included in this as above
    },
    {
        "category": "Category 2",
        "series_1": 11,
        "series_2": 22,
        ..... if 'series_3', 'series_4' etc. existed, it would be included in this as above
    },
    {
        "category": "Category 3",
        "series_1": 120,
        "series_2": 127,
        ..... if 'series_3', 'series_4' etc. existed, it would be included in this as above
    }
]
arrays javascript json key-value
2021-11-24 02:19:06
6

Najlepsza odpowiedź

2

Aby przetworzyć logiki kilka właściwości, można wykonać cykl dla każdej właściwości, i sprawdzić, czy pasuje do wyrażenia regularnego series_\d+. Jeśli tak, to wiesz, że jest to właściwość, którą chcesz powiększyć, i taktujesz go odpowiednio (konieczne jest również sprawdzenie, czy właściwości, jak wskazano Jayce444).

W poniższym rozwiązaniu używanyArray.reduce. W funkcji przekładni ona sprawdzić, czy zawiera macierz dysków element z tym samym category własność, jak ta, przez którą przechodzi obecnie cykl. Jeśli tak się stanie, będzie to prowadzić do wzrostu odpowiednich właściwości. W przeciwnym razie przesuwa bieżący element w tablicy pamięci.

arrOne=[{series_1:25,category:"Category 1",series_2:50},{series_1:11,category:"Category 2",series_2:22},{series_1:32,category:"Category 1",series_2:74},{series_1:74,category:"Category 3",series_2:98},{series_1:46,category:"Category 3",series_2:29,series_3:50}];

const res = arrOne.reduce((a, b) => {
  let found = a.find(e => e.category == b.category)
  if (found) {
    Object.keys(b).forEach(e => {
      if (/series_\d+/g.test(e)) found[e] = found[e] ? found[e] + b[e] : b[e];
    })
  } else {
    a.push(b)
  }
  return a;
}, [])

console.log(res)

2021-11-24 02:38:52

To podejście jest zakłócony, gdy wszystkie obiekty nie mają takich samych kolejnych kluczy. Na przykład, jeśli dodasz series_3: 5 tylko dla pierwszego obiektu, to kończy się tak series_3: NaN w wyniku.
Jayce444

Czy nie będzie to pominąć nowe klucze serii, które zostały dodane do tej samej kategorii w nowszych obiektach? Jest to również O(n^2) (chyba)
Phil

@Phil, dziękujemy za zgłoszenie. Zaktualizowałem swoją odpowiedź.
Spectric
1

Coś takiego może się udać.

arrOne = [ { "series_1": 25, "category": "Category 1", "series_2": 50 }, { "series_1": 11, "category": "Category 2", "series_2": 22 }, { "series_1": 32, "category": "Category 1", "series_2": 74 }, { "series_1": 74, "category": "Category 3", "series_2": 98 }, { "series_1": 46, "category": "Category 3", "series_2": 29 },];

const result = [];
arrOne.reduce((acc, {category, ...series}) => {
  if (acc.has(category)) {
    Object.entries(series).forEach(([key, value]) => {
      if (key.startsWith('series_')) {
        acc.get(category)[key] = (acc.get(category)[key] || 0) + value;
      }
    });
  } else {
    const item = {category, ...series};
    result.push(item);
    acc.set(category, item);
  }
  return acc;
}, new Map());

console.log(result);

2021-11-24 02:27:40

Nie jestem pewny co do reduktora z efektami ubocznymi (result mutacja)
Phil
0

Utwórz mapę do mapowania sum szeregów według kategorii.

Następnie utwórz tablicę z tej karty z kluczami w postaci category

const arr1 = [{"series_1":25,"category":"Category 1","series_2":50},{"series_1":11,"category":"Category 2","series_2":22},{"series_1":32,"category":"Category 1","series_2":74},{"series_1":74,"category":"Category 3","series_2":98},{"series_1":46,"category":"Category 3","series_2":29}]

const t1 = performance.now()

const cats = arr1.reduce((map, { category, ...series }) =>
  map.set(category, Object.entries(series)
    .reduce((s, [ key, count ]) => ({
      ...s,
      [ key ]: (s[key] ?? 0) + count
    }), map.get(category) ?? {})
  ), new Map())

const allCategoriesAndValues = Array.from(cats, ([ category, series ]) => ({
  category,
  ...series
}))

const t2 = performance.now()

console.info(allCategoriesAndValues)
console.log(`Took ${t2 - t1}ms`)
.as-console-wrapper { max-height: 100% !important; }

2021-11-24 02:32:20
0

Zrobię to w ten sposób...

const arrOne = 
  [ { series_1: 25, category: 'Category 1', series_2: 50 } 
  , { series_1: 11, category: 'Category 2', series_2: 22 } 
  , { series_1: 32, category: 'Category 1', series_2: 74 } 
  , { series_1: 74, category: 'Category 3', series_2: 98 } 
  , { series_1: 46, category: 'Category 3', series_2: 29 } 
  ] 

console.time('chrono')

const allCategoriesAndValues =
  Object.entries(
  arrOne.reduce((r,{ category, ...series })=>
    {
    let cat = r[category] = r[category] ?? {} 
    Object.entries(series).forEach(([sName,val]) => cat[sName] = (cat[sName] ?? 0) + val);
    return r
    },{})
  ).map(([category,series])=>({category,...series}))

console.timeEnd('chrono')

console.log( allCategoriesAndValues )
.as-console-wrapper {max-height: 100%!important;top:0 }

2021-11-24 02:47:52
0

Można po prostu wykonać iteracji dla tablicy obiektów, a następnie na kluczu każdego obiektu, przechowywanych w obiekcie buforowym. Trzeba tylko sprawdzić dostępność każdego klucza i dodać go, jeśli go nie ma, albo można po prostu połączyć klucze falsey na wartość domyślną, jak ja to zrobiłem. Ja usuwam klucz kategorii z obiektu po tym, jak otrzymam jego wartość, aby nie musiałem próbować go pominąć podczas iteracji z kluczem.

const arrOne = [
  {"series_1": 25, "category": "Category 1", "series_2": 50},
  {"series_1": 11, "category": "Category 2", "series_2": 22},
  {"series_1": 32, "category": "Category 1", "series_2": 74},
  {"series_1": 74, "category": "Category 3", "series_2": 98},
  {"series_1": 46, "category": "Category 3", "series_2": 29},
];

let buffer = {};
arrOne.forEach(i=>{
  let c = i.category;
  buffer[c] = buffer[c] || {};
  delete i.category;
  Object.keys(i).forEach(k=>{
    buffer[c][k] = buffer[c][k] || 0;
    buffer[c][k] += i[k];
  });
});

console.log(buffer);

let final = Object.keys(buffer).map(k=>{return {[k]: buffer[k]}});
console.log(final);

Jeśli nie musisz mieć to w tablicy, ostatni krok jest opcjonalny. On jest tylko do konwersji obiektu do tablicy.

2021-11-24 02:31:18
0

Oto jak ja bym to zrobił

const res = arrOne.reduce((acc, { category, ...vals }) => {
    if (acc[category]) {
        Object.entries(vals).forEach(([ key, val ]) => acc[category][key] = acc[category][key] ? acc[category][key] + val : val);

    } else {
        acc[category] = vals;

    }

    return acc;
}, {});
2021-11-24 03:11:13

W innych językach

Ta strona jest w innych językach

Русский
..................................................................................................................
Italiano
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................