Я пытаюсь объединить данные на любом дублирующем ключе, но также переписать объект данных.

Я пытаюсь объединить массив значений в зависимости от того, имеет ли каждый объект одинаковое «время». После чего я хотел бы соединить каждое значение в элементах с именем.

Я думаю, что самый простой способ показать это через необработанные данные, которые я надеюсь преобразовать, поэтому я хотел бы преобразовать следующее;

var data = [{
  "item": ["1", "2"],
  "time": "12-15",
  "name": "ben"
}, {
  "item": ["3", "4"],
  "time": "12-15",
  "name": "bill"
}, {
  "item": ["1", "2", "3"],
  "time": "15-18",
  "name": "ben"

}, {
  "item": ["4", "5", "6"],
  "time": "15-18",
  "name": "bill"
}];

В

var result = [{
  "time": "12-15",
  "ben": ["1", "2"],
  "bill": ["3", "4"]
},
{
  "time": "15-18",
  "ben": ["1", "2", "3"],
  "bill": ["4", "5", "6"]
}]

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

Любая помощь высоко ценится!

var data = [{
  "item": ["1", "2"],
  "time": "12-15",
  "name": "ben"
}, {
  "item": ["3", "4"],
  "time": "12-15",
  "name": "bill"
}, {
  "item": ["1", "2", "3"],
  "time": "15-18",
  "name": "ben"

}, {
  "item": ["4", "5", "6"],
  "time": "15-18",
  "name": "bill"

}];



var seen = {};
var result = data.filter(function(entry) {
  var previous;

  // Have we seen this label before?
  if (seen.hasOwnProperty(entry.time)) {

    // Yes, grab it and add this data to it
    previous = seen[entry.time];
    previous.item.push(entry.item);

    // Don't keep this entry, we've merged it into the previous one
    return false;
  }
  //console.log(seen)
  // entry.data probably isn't an array; make it one for consistency
  if (!Array.isArray(entry.item)) {
    entry.item = [entry.item];
  }

  // Remember that we've seen it
  seen[entry.time] = entry;

  // Keep this one, we'll merge any others that match into it
  return true;
});

console.log(result)
2
ggt 13 Дек 2016 в 18:31

6 ответов

Лучший ответ

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

var data = [{ "item": ["1", "2"], "time": "12-15", "name": "ben" }, { "item": ["3", "4"], "time": "12-15", "name": "bill" }, { "item": ["1", "2", "3"], "time": "15-18", "name": "ben" }, { "item": ["4", "5", "6"], "time": "15-18", "name": "bill" }],
    result = [];

data.forEach(function (a) {
    if (!this[a.time]) {
        this[a.time] = { time: a.time };
        result.push(this[a.time]);
    }
    this[a.time][a.name] = (this[a.time][a.name] || []).concat(a.item);
}, Object.create(null));

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

Или с ES6 вы можете использовать Map.

var data = [{ "item": ["1", "2"], "time": "12-15", "name": "ben" }, { "item": ["3", "4"], "time": "12-15", "name": "bill" }, { "item": ["1", "2", "3"], "time": "15-18", "name": "ben" }, { "item": ["4", "5", "6"], "time": "15-18", "name": "bill" }],
    map = new Map,
    result = [];

data.forEach(a => {
    var o = map.get(a.time);
    if (!o) {
        o = { time: a.time };
        map.set(a.time, o);
        result.push(o);
    }
    o[a.name] = (o[a.name] || []).concat(a.item);
});

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
1
Nina Scholz 13 Дек 2016 в 18:12

Вы можете сделать следующее:

var data = [{
  "item": ["1", "2"],
  "time": "12-15",
  "name": "ben"
}, {
  "item": ["3", "4"],
  "time": "12-15",
  "name": "bill"
}, {
  "item": ["1", "2", "3"],
  "time": "15-18",
  "name": "ben"

}, {
  "item": ["4", "5", "6"],
  "time": "15-18",
  "name": "bill"
}],

interim = data.reduce((h,d) => (h[d.time] = h[d.time] ? h[d.time].concat({[d.name]: d.item})
                                                      : [{[d.name]: d.item}],h),{}),
 result = Object.keys(interim)
                .map(k => Object.assign({time: k},...interim[k]));
console.log(result);
0
Redu 13 Дек 2016 в 16:04

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

class DefaultMap extends Map {
    constructor(defaultConstructor) {
        super();
        this.defaultConstructor = defaultConstructor;
    }

    get(key) {
        if (this.has(key)) {
            return super.get(key);
        }

        const def = this.defaultConstructor();
        this.set(key, def);
        return def;
    }
}

function groupBy(collection, key) {
    const groups = new DefaultMap(() => []);

    for (const item of collection) {
        const itemKey = key(item);
        const group = groups.get(itemKey);

        group.push(item);
    }

    return groups;
}

Тогда вы можете просто:

const result =
    groupBy(data, entry => entry.time).entries().map(
        ([time, entries]) => {
            const group = {time};

            entries.forEach(entry => {
                group[entry.name] = entry.item;
            });

            return group;
        }
    );
0
Ry- 13 Дек 2016 в 16:15

Вы можете сделать это просто с помощью map () и filter () и внутреннего цикла следующим образом:

var data = [{
  "item": ["1", "2"],
  "time": "12-15",
  "name": "ben"
}, {
  "item": ["3", "4"],
  "time": "12-15",
  "name": "bill"
}, {
  "item": ["1", "2", "3"],
  "time": "15-18",
  "name": "ben"
}, {
  "item": ["4", "5", "6"],
  "time": "15-18",
  "name": "bill"
}];

var skel = data.map(x => x.time).filter((x,i,arr) => arr.indexOf(x) === i).map(x => ({"time" : x}));
var result = skel.map(x => {
  data.forEach(y => {
    if(x.time === y.time)
      x[y.name] = y.item;
  })
  return x;
} )
console.log(result);
0
kevin ternet 13 Дек 2016 в 16:02

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

Примечание. использует синтаксис ES6, но этот код можно легко преобразовать в ES5.

const data = [{
  "item": ["1", "2"],
  "time": "12-15",
  "name": "ben"
}, {
  "item": ["3", "4"],
  "time": "12-15",
  "name": "bill"
}, {
  "item": ["1", "2", "3"],
  "time": "15-18",
  "name": "ben"

}, {
  "item": ["4", "5", "6"],
  "time": "15-18",
  "name": "bill"

}];

// Get a list of unique times
const getTimes = data => data.reduce((a, c) => {
  if (!a.includes(c.time)) {
    a.push(c.time);
  }      
  
  return a;
}, []);

// Merge the data into a single list using the times list as index
const mergeData = (data, times) => times.map(time => {
  const obj = {};
  obj.time = time;
  
  data.forEach(record => {
    if (record.time === time) {
      obj[record.name] = record.item;
    }
  });
  
  return obj;
});

const times = getTimes(data);
const result = mergeData(data, times);

console.log(result);
1
David Gomez 13 Дек 2016 в 18:58

Попробуй это

var timeGroup = _.groupBy(data,"time");

_.mapObject(timeGroup,function(val,key){
var benArray = _.flatten(_.values(_.pick(_.findWhere(val,   {name:"ben"}),"item")));
var billArray = _.flatten(_.values(_.pick(_.findWhere(val,{name:"bill"}),"item")));
console.log({"time" : key,"ben" : benArray , "bill" : billArray })
})
0
Vignesh Murugan 13 Дек 2016 в 16:15