JavaScript - Группировать массив по значению и до двух уровней - PullRequest
2 голосов
/ 16 июня 2020

Рассмотрим следующий входной массив:

var input = [{
  "index": "1",
  "location": "London",
  "source": "1-source"
}, {
  "index": "1",
  "location": "New York",
  "source": "1-souce"
}, {
  "index": "1",
  "location": "London",
  "source": "2-source"
}, {
  "index": "2",
  "location": "London",
  "source": "3-source"
}, {
  "index": "2",
  "location": "London",
  "source": "4-source"
}, {
  "index": "1",
  "location": "Japan",
  "source": "1-source"
}, {
  "index": "3",
  "location": "London",
  "source": "5-source"
}, {
  "index": "3",
  "location": "London",
  "source": "6-source"
}, {
  "index": "4",
  "location": "London",
  "source": "7-source"
}, {
  "index": "4",
  "location": "London",
  "source": "8-source"
}, {
  "index": "2",
  "location": "Japan",
  "source": "2-souce"
}, {
  "index": "1",
  "location": "New York",
  "source": "2-source"
}, {
  "index": "2",
  "location": "Japan",
  "source": "3-souce"
}, {
  "index": "2",
  "location": "Japan",
  "source": "4-source"
}, {
  "index": "3",
  "location": "Japan",
  "source": "Press Pumps"
}, {
  "index": "2",
  "location": "New York",
  "source": "3-source"
}, {
  "index": "3",
  "location": "Japan",
  "source": "Camera01"
}]

, который должен быть сгруппирован в следующий массив:

var output = [{
  "name": "London",
  "children": [{
          "name": "1",
          "children": [{
              "name": "1-source"
          }, {
              "name": "2-source"
          }]
      },
      {
          "name": "2",
          "children": [{
              "name": "3-source"
          }, {
              "name": "4-source"
          }]
      },
      {
          "name": "3",
          "children": [{
              "name": "5-source"
          }, {
              "name": "6-source"
          }]
      },
      {
          "name": "4",
          "children": [{
              "name": "7-source"
          }, {
              "name": "8-source"
          }]
      }
  ]
},
{
  "name": "New York",
  "children": [{
          "name": "1",
          "children": [{
              "name": "1-souce"
          }, {
              "name": "2-source"
          }]
      },
      {
          "name": "2",
          "children": [{
              "name": "3-source"
          }]
      }
  ]
},
{
  "name": "Japan",
  "children": [{
          "name": "1",
          "children": [{
              "name": "1-source"
          }]
      },
      {
          "name": "2",
          "children": [{
              "name": "2-souce"
          }, {
              "name": "3-souce"
          }, {
              "name": "4-source"
          }]
      },
      {
          "name": "3",
          "children": [{
              "name": "Press Pumps"
          }, {
              "name": "Camera01"
          }]
      }
  ]
}
];

То, что я пробовал:

var groupBy = function (xs, key) {
  return xs.reduce(function (rv, x) {        
    var tmp = rv.find(r => r.name == x[key]) || { name: x[key], children: []};
    if (tmp.children.length == 0) {
      rv.push(tmp);
    }    
    tmp.children.push(x);
    return rv;
  }, []);
};
var result = groupBy(input, 'location');
result.forEach(function(r){
  //console.log(r);
  r.children = groupBy(r.children, 'index');
  r.children.forEach(function(c){
    //console.log(c);
    c.children = groupBy(c.children,'source');
    c.children.forEach(function(f){
      delete f.children;
      //console.log(f);
    })
  })
});
console.log(result);

Я думаю, что forEach - это перебор !? Я просто хочу знать, есть ли лучший способ сделать это. Как ты думаешь, мне стоит попробовать что-нибудь вроде рекурсии?

Ответы [ 2 ]

1 голос
/ 17 июня 2020
• 1000 Эти задачи могут быть решены «на месте» за счет стоимости ЦП или путем сопоставления за счет памяти.

/*
  maps tree structure like:
  {
    "London": {
      "1": [{"name": "2-source"}]
    }
  }
*/
const locMap = {};
for (item of input) {
  locMap[item.location] = locMap[item.location] || {};
  locMap[item.location][item.index] = locMap[item.location][item.index] || [];
  locMap[item.location][item.index].push({name: item.source});
}

// composes desired object from tree structure above
const output = Object.entries(locMap).map(([locName, idxMap]) => {
  return {
    name: locName,
    children: Object.entries(idxMap).map(([index, sources]) => {
      return {
        name: index,
        children: sources
      }
    })
  }
})

console.log(output);
<script>
var input = [{
  "index": "1",
  "location": "London",
  "source": "1-source"
}, {
  "index": "1",
  "location": "New York",
  "source": "1-souce"
}, {
  "index": "1",
  "location": "London",
  "source": "2-source"
}, {
  "index": "2",
  "location": "London",
  "source": "3-source"
}, {
  "index": "2",
  "location": "London",
  "source": "4-source"
}, {
  "index": "1",
  "location": "Japan",
  "source": "1-source"
}, {
  "index": "3",
  "location": "London",
  "source": "5-source"
}, {
  "index": "3",
  "location": "London",
  "source": "6-source"
}, {
  "index": "4",
  "location": "London",
  "source": "7-source"
}, {
  "index": "4",
  "location": "London",
  "source": "8-source"
}, {
  "index": "2",
  "location": "Japan",
  "source": "2-souce"
}, {
  "index": "1",
  "location": "New York",
  "source": "2-source"
}, {
  "index": "2",
  "location": "Japan",
  "source": "3-souce"
}, {
  "index": "2",
  "location": "Japan",
  "source": "4-source"
}, {
  "index": "3",
  "location": "Japan",
  "source": "Press Pumps"
}, {
  "index": "2",
  "location": "New York",
  "source": "3-source"
}, {
  "index": "3",
  "location": "Japan",
  "source": "Camera01"
}]
</script>
1 голос
/ 17 июня 2020

Надеюсь, это вам поможет.

var res = input.reduce((res, { index, location, source }) => {
  var place = res.find(p => p.name === location)
  if (!place) {
    place = { name: location, children: [] }
    res.push(place)
  }
  var child = place.children.find(ch => ch.name === index)
  if (!child) {
    child = { name: index, children: [] }
    place.children.push(child)
  }
  child.children.push({ name: source })
  return res
}, [])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...