将具有相同键值的对象合并为数组

3

很抱歉,如果json不完美,那是因为我试图将它输入到Stackoverflow窗口中... 无论如何,从下面可以看出,我想将数组中所有单独的对象合并到具有匹配url的第一个数组中。一旦它们被合并,所有其他对象都需要从数组中删除。

var myArray = [{  id: '123', url: 'http://foo.com/1.jpg', size: 7, qty: 1},{ id: '345', url: 'http://foo.com/5.jpg', color: 'blue', qty: 5},{ id: '678', url: 'http://foo.com/1.jpg', size: 8, qty: 4}];

我需要将这个数组转化成... 如下所示,具有匹配URL的对象现在已经移动到第一个匹配对象的“variations”键中。之后它们不再单独出现。它们本质上都匹配在一起,并合并到同一个对象中。

var myArray = [{ 
 id: '123',
 url: 'http://foo.com/1.jpg',
 variations:[
     {
       id : '123'
       size : 7,
       qty: 1
     }, 
     {
       id : '678'
       size : 8,
       qty: 4
     }],
{
 id: '345',
 url: 'http://foo.com/5.jpg',
 color: 'blue',
 qty: 5
}];

到目前为止,我有类似于这样的东西:但这只是一个正在进行中的工作。在将其推向终点时遇到了麻烦。

myArray.forEach(function(product, index){
  var sizeVariations = [];
  var currentSearch = product.url;
  var filteredArray = processedProducts.filter(function( obj ) {
    return obj.primary_image === currentSearch;
  });

  if(filteredArray){
    filteredArray.forEach(function(data, index){
      sizeVariations.push({
        id : data.id,
        size : data.size,
        quantity : data.qty
      });
    });
  }
});

1
你尝试过什么?你需要什么帮助?请参阅如何创建一个最小化、完整和可验证的示例 - RobG
我真的不建议创建这样一个碎片化的数据结构(即一些条目带有“变体”,而另一些则没有)。此外,您如何决定哪个“id”位于合并条目之外的“变体”中? - Phil
基本上,如果它们具有匹配的URL值,则我需要所有信息都在同一个对象中。 - jremi
4个回答

1
你可以做类似的事情;我不会将id保留在顶层,因为这看起来像是数据的重复。

var myArray = [
{ 
 id: '123',
 url: 'http://foo.com/1.jpg',
 size: 7,
 qty: 1
},
{
 id: '345',
 url: 'http://foo.com/5.jpg',
 color: 'blue',
 qty: 5
},
{
 id: '678',
 url: 'http://foo.com/1.jpg',
 size: 8,
 qty: 4
}];

function mergeObjects(arr)
{
  var resultArray = [];
  var urls = [];
  for(var item in arr)
  {
    var itemIndex = urls.indexOf(arr[item].url);
    if(itemIndex == -1)
    {
      urls.push(arr[item].url);
      var obj = {};
      obj.url = arr[item].url;
      obj.variations = [];
      var variationData = {};
      variationData.id = arr[item].id;
      if(arr[item].size !== undefined)
      {
        variationData.size = arr[item].size;
      }
      if(arr[item].qty !== undefined)
      {
        variationData.qty = arr[item].qty;
      }
      if(arr[item].color !== undefined)
      {
        variationData.color = arr[item].color;
      }
     
      obj.variations.push(variationData);
      resultArray.push(obj);
    }
    else
    {
      var variationData = {};
      variationData.id = arr[item].id;
      if(arr[item].size !== undefined)
      {
        variationData.size = arr[item].size;
      }
      if(arr[item].qty !== undefined)
      {
        variationData.qty = arr[item].qty;
      }
      if(arr[item].color !== undefined)
      {
        variationData.color = arr[item].color;
      }
      resultArray[itemIndex].variations.push(variationData)
    }
    
  }
  return resultArray;
}

console.log(mergeObjects(myArray));


1
这正好做我所需要的。我已经修改它以适应我的需求。谢谢。 - jremi
1
这两个短语在我看来好像是矛盾的:P - trincot

0

我觉得一个更好的数据结构应该是以url为键。

const myArray = [{"id":"123","url":"http://foo.com/1.jpg","size":7,"qty":1},{"id":"345","url":"http://foo.com/5.jpg","color":"blue","qty":5},{"id":"678","url":"http://foo.com/1.jpg","size":8,"qty":4}]

const urlMap = myArray.reduce((byUrl, entry) => {
  const entryWithoutUrl = Object.assign({}, entry)
  delete entryWithoutUrl.url

  if (Array.isArray(byUrl[entry.url])) {
    byUrl[entry.url].push(entryWithoutUrl)
  } else {
    byUrl[entry.url] = [entryWithoutUrl]
  }
  return byUrl
}, Object.create(null))

const newArray = Object.keys(urlMap).map(url => ({
  url: url,
  variations: urlMap[url]
}))

console.info(newArray)


0

我认为你可以先将所有的URL收集到一个对象中,以确保唯一性,然后再将其转换为数组,就像这样:

function Merge(arr) {
    var obj = {};

    for (var elem of arr) {
        if (obj[elem.url] == undefined) {
            obj[elem.url] = {
                id: elem.id,
                variations: [],
                url: elem.url
            };
        }

        obj[elem.url].variations.push(elem);
        delete elem.url;
    }

    var ans = [];
    for (var elem in obj) {
        var tmp = {
            id: obj[elem].id,
            url: elem
        };
        if(obj[elem].variations.length > 1) 
            tmp.variations = obj[elem].variations;
        else {
            tmp.color = obj[elem].variations[0].color;
            tmp.qty = obj[elem].variations[0].qty;
        }
        ans.push(tmp);
    }

    return ans;
}

0
在这个例子中,我将问题分解为两个较小的问题,以提高效率,避免迭代数组以检查URL是否已存在,然后一旦所有内容都按URL分组,我们将结果对象转换回数组,并将每个键作为数组中的一个项。
如果您使用函数式编程,可以将这些函数组合在一起。
compose(objectToArray, sortByUnique)('url', myArray)

var myArray = [
  { id: '123', url: 'http://foo.com/1.jpg', qty: 1, size: 7 },
  { id: '345', url: 'http://foo.com/5.jpg', qty: 5, color: 'blue' },
  { id: '678', url: 'http://foo.com/1.jpg', qty: 4, size: 8 },
  { id: '69',  url: 'http://foo.com/1.jpg', qty: 4, size: 8 }
]

function sortByUnique(unique, array) {
  // group array by unique key into an object
  return array.reduce((acc, x) => {
    let key = x[unique]
    delete x[unique]
    if (acc[key]) {
      if (!acc[key].variations) {
        let old = acc[key]
        acc[key] = {
          variations: [old, x]
        }
      }
      else {
        acc[key].variations.push(x)
      }
    }
    else {
      acc[key] = x
    }
    return acc
  }, {})
}

function objectToArray(obj) {
  return Object.keys(obj).map(
    k => Object.assign(
      { url: k },
      obj[k]
    ))
}

console.log(
  objectToArray(sortByUnique('url', myArray))
)


如果URL被分组在数组中会发生什么...?{ url : ['http://foo.com/1.jpg'] } - jremi
这段代码中没有示例,因此它会破坏上面的代码。 - synthet1c
是的,我知道,我很抱歉,但我想知道你能否演示如何使用数组工作。 - jremi
它需要完全重新设计,因为它使用单一的URL作为分组的唯一键,除非它只是URL数组中的单个元素['goo.gl/something'],但是这样你也会失去代码的可重用性。 - synthet1c

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接