Подтвердить что ты не робот

Группировка элементов массива с использованием объекта

Мой массив выглядит примерно так:

myArray = [
  {group: "one", color: "red"},
  {group: "two", color: "blue"},
  {group: "one", color: "green"},
  {group: "one", color: "black"}
]

Я хочу преобразовать это в:

myArray = [
  {group: "one", color: ["red", "green", "black"]}
  {group: "two", color: ["blue"]}
]

Итак, в основном, группа за group.

Я пытаюсь:

for (i in myArray){
  var group = myArray[i].group;
  //myArray.push(group, {???})
}

Я просто не знаю, как справиться с группировкой похожих групповых значений.

4b9b3361

Ответ 1

Во-первых, в JavaScript обычно не рекомендуется перебирать массивы с помощью for ... in. См. Почему используется "для... в" с итерацией массива плохая идея? для деталей.

Итак, вы можете попробовать что-то вроде этого:

var groups = {};
for (var i = 0; i < myArray.length; i++) {
  var groupName = myArray[i].group;
  if (!groups[groupName]) {
    groups[groupName] = [];
  }
  groups[groupName].push(myArray[i].color);
}
myArray = [];
for (var groupName in groups) {
  myArray.push({group: groupName, color: groups[groupName]});
}

Использование промежуточного объекта groups здесь помогает ускорить процесс, потому что он позволяет избежать циклов вложенности для поиска по массивам. Кроме того, поскольку groups - это объект (а не массив), итерация по нему с использованием for ... in является подходящей.

Добавление

FWIW, если вы хотите избежать дублирования записей цвета в результирующих массивах, вы можете добавить оператор if над строкой groups[groupName].push(myArray[i].color); для защиты от дубликатов. Используя jQuery, он будет выглядеть следующим образом:

if (!$.inArray(myArray[i].color, groups[groupName])) {
  groups[groupName].push(myArray[i].color);
}

Без jQuery вы можете добавить функцию, которая делает то же самое, что и jQuery inArray:

Array.prototype.contains = function(value) {
  for (var i = 0; i < this.length; i++) {
    if (this[i] === value)
      return true;
  }
  return false;
}

а затем используйте его следующим образом:

if (!groups[groupName].contains(myArray[i].color)) {
  groups[groupName].push(myArray[i].color);
}

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

Ответ 2

Начните с создания сопоставления имен групп со значениями. Затем преобразуйте в желаемый формат.

var myArray = [
    {group: "one", color: "red"},
    {group: "two", color: "blue"},
    {group: "one", color: "green"},
    {group: "one", color: "black"}
];

var group_to_values = myArray.reduce(function (obj, item) {
    obj[item.group] = obj[item.group] || [];
    obj[item.group].push(item.color);
    return obj;
}, {});

var groups = Object.keys(group_to_values).map(function (key) {
    return {group: key, color: group_to_values[key]};
});

var pre = document.createElement("pre");
pre.innerHTML = "groups:\n\n" + JSON.stringify(groups, null, 4);
document.body.appendChild(pre);

Ответ 3

Использовать метод lodash groupby

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

Итак, с lodash вы можете получить то, что хотите, в одной строке. См. Ниже

let myArray = [
  {group: "one", color: "red"},
  {group: "two", color: "blue"},
  {group: "one", color: "green"},
  {group: "one", color: "black"},
]
let grouppedArray=_.groupBy(myArray,'group')
console.log(grouppedArray)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

Ответ 4

Один из вариантов:

var res = myArray.reduce(function(groups, currentValue) {
    if ( groups.indexOf(currentValue.group) === -1 ) {
      groups.push(currentValue.group);
    }
    return groups;
}, []).map(function(group) {
    return {
        group: group,
        color: myArray.filter(function(_el) {
          return _el.group === group;
        }).map(function(_el) { return _el.color; })
    }
});

http://jsfiddle.net/dvgwodxq/

Ответ 5

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

var array = [{ group: "one", color: "red" }, { group: "two", color: "blue" }, { group: "one", color: "green" }, { group: "one", color: "black" }],
    groups = Object.create(null),
    grouped = [];

array.forEach(function (o) {
    if (!groups[o.group]) {
        groups[o.group] = [];
        grouped.push({ group: o.group, color: groups[o.group] });
    }
    groups[o.group].push(o.color);
});

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

Ответ 6

myArray = [
  {group: "one", color: "red"},
  {group: "two", color: "blue"},
  {group: "one", color: "green"},
  {group: "one", color: "black"}
];


let group = myArray.map((item)=>  item.group ).filter((item, i, ar) => ar.indexOf(item) === i).sort((a, b)=> a - b).map(item=>{
    let new_list = myArray.filter(itm => itm.group == item).map(itm=>itm.color);
    return {group:item,color:new_list}
});
console.log(group);

Ответ 7

Эта версия использует преимущества того, что ключи объектов уникальны. Мы обрабатываем исходный массив и собираем цвета по группе в новом объекте. Затем создайте новые объекты из этой группы → массив массивов цветов.

var myArray = [{
      group: "one",
      color: "red"
    }, {
      group: "two",
      color: "blue"
    }, {
      group: "one",
      color: "green"
    }, {
      group: "one",
      color: "black"
    }];

    //new object with keys as group and
    //color array as value
    var newArray = {};

    //iterate through each element of array
    myArray.forEach(function(val) {
      var curr = newArray[val.group]

      //if array key doesnt exist, init with empty array
      if (!curr) {
        newArray[val.group] = [];
      }

      //append color to this key
      newArray[val.group].push(val.color);
    });

    //remove elements from previous array
    myArray.length = 0;

    //replace elements with new objects made of
    //key value pairs from our created object
    for (var key in newArray) {
      myArray.push({
        'group': key,
        'color': newArray[key]
      });
    }

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

Ответ 8

var array = [{
      id: "123",
      name: "aaaaaaaa"
    }, {
      id: "123",
      name: "aaaaaaaa"
    }, {
      id: '456',
      name: 'bbbbbbbbbb'
    }, {
      id: '789',
      name: 'ccccccccc'
    }, {
      id: '789',
      name: 'ccccccccc'
    }, {
      id: '098',
      name: 'dddddddddddd'
    }];
//if you want to group this array
group(array, key) {
  console.log(array);
  let finalArray = [];
  array.forEach(function(element) {
    var newArray = [];
    array.forEach(function(element1) {
      if (element[key] == element1[key]) {
          newArray.push(element)
      }
    });
    if (!(finalArray.some(arrVal => newArray[0][key] == arrVal[0][key]))) {
        finalArray.push(newArray);
    }
  });
  return finalArray
}
//and call this function
groupArray(arr, key) {
  console.log(this.group(arr, key))
}

Ответ 9

Еще один вариант - использовать reduce() и new Map() для группировки массива. Используйте Spread syntax для преобразования заданного объекта в массив.

var myArray = [{"group":"one","color":"red"},{"group":"two","color":"blue"},{"group":"one","color":"green"},{"group":"one","color":"black"}]

var result = [...myArray.reduce((c, {group,color}) => {
  if (!c.has(group)) c.set(group, {group,color: []});
  c.get(group).color.push(color);
  return c;
}, new Map()).values()];

console.log(result);

Ответ 10

Вы можете сделать что-то вроде этого:

function convert(items) {
    var result = [];

    items.forEach(function (element) {
        var existingElement = result.filter(function (item) {
            return item.group === element.group;
        })[0];

        if (existingElement) {
            existingElement.color.push(element.color);
        } else {
            element.color = [element.color];
            result.push(element);
        }

    });

    return result;
}

Ответ 11

Использование массива reduce и findIndex методы, это может быть достигнуто.

var myArray = [{
  group: "one",
  color: "red"
}, {
  group: "two",
  color: "blue"
}, {
  group: "one",
  color: "green"
}, {
  group: "one",
  color: "black"
}];

var transformedArray = myArray.reduce((acc, arr) => {
  var index = acc.findIndex(function(element) {
    return element.group === arr.group;
  });
  if (index === -1) {
    return acc.push({
      group: arr.group,
      color: [arr.color]
    });
  }
  
  acc[index].color.push(arr.color);
  return acc;
}, []);

console.log(transformedArray);

Ответ 12

Вы можете расширить функциональность массива с помощью следующего:

Array.prototype.groupBy = function(prop) {
  var result = this.reduce(function (groups, item) {
      const val = item[prop];
      groups[val] = groups[val] || [];
      groups[val].push(item);
      return groups;
  }, {});
  return Object.keys(result).map(function(key) {
      return result[key];
  });
};

Пример использования:

/* re-usable function */
Array.prototype.groupBy = function(prop) {
  var result = this.reduce(function (groups, item) {
      const val = item[prop];
      groups[val] = groups[val] || [];
      groups[val].push(item);
      return groups;
  }, {});
  return Object.keys(result).map(function(key) {
      return result[key];
  });
};

var myArray = [
  {group: "one", color: "red"},
  {group: "two", color: "blue"},
  {group: "one", color: "green"},
  {group: "one", color: "black"}
]

console.log(myArray.groupBy('group'));

Ответ 13

Попробуйте (h = {})

myArray.forEach(x=> h[x.group]= (h[x.group]||[]).concat(x.color) );
myArray = Object.keys(h).map(k=> ({group:k, color:h[k]}))

let myArray = [
  {group: "one", color: "red"},
  {group: "two", color: "blue"},
  {group: "one", color: "green"},
  {group: "one", color: "black"},
];

let h={};

myArray.forEach(x=> h[x.group]= (h[x.group]||[]).concat(x.color) );
myArray = Object.keys(h).map(k=> ({group:k, color:h[k]}))

console.log(myArray);