0

I have an array of objects with the following structure:

var items = [
  {
    attributes: [
      {
        type: "Size",
        value: "Small"
      },
      {
        type: "Color",
        value: "Black"
      }
    ]
  },
  {
    attributes: [
      {
        type: "Size",
        value: "Small"
      },
      {
        type: "Color",
        value: "White"
      }
    ]
  },
  {
    attributes: [
      {
        type: "Size",
        value: "Medium"
      },
      {
        type: "Color",
        value: "Black"
      }
    ]
  },
  {
    attributes: [
      {
        type: "Size",
        value: "Medium"
      },
      {
        type: "Color",
        value: "White"
      }
    ]
  }
];

My goal is to extract all the "value" property with the same "type". For example, the type "Size" has the following values: Small, Medium. After that, I want to create a new list with the following structure:

 var results = [
  {
    type: "Size",
    values: ["Small", "Medium"]
  },
  {
    type: "Color",
    values: ["White", "Black"]
  }
];

This is my current code:

var results = items.map((item, index) => {
  return item.attributes.map(attribute => {
    let value = [];
    value.push(attribute.value);
    return {
      type: attribute.type,
      value: attribute.value
    };
  });
});
2

You can use reduce and Set

  • first loop through the items array
  • For each attribute we map the type as key on our final object and add the values to respective keys, since we want to keep only unique values so the we use Set
  • Now our final looks like {type: { type, value }} but our desired format is { type, size} so we use Object.values() to get {type, value} from final and then we map it to desired format

var items = [{attributes: [{type: "Size",value: "Small"},{type: "Color",value: "Black"}]},{attributes: [{type: "Size",value: "Small"},{type: "Color",value: "White"}]},{attributes: [{type: "Size",value: "Medium"},{type: "Color",value: "Black"}]},{attributes: [{type: "Size",value: "Medium"},{type: "Color",value: "White"}]}];


let final = items.reduce((op, {attributes}) => {
  attributes.forEach(({type, value}) => {
    op[type] = op[type] || {type, value: new Set()}
    op[type].value.add(value)
  })
  return op
},{})

let output = Object.values(final).map(({type, value}) => ({type, value:[...value]}))

console.log(output)

  • Hi, thanks for the reply! Is it possible if you can add some comments to your code so that I can understand? :> – Issaki 15 hours ago
  • 1
    @Issaki yes sure, i have added a short explanation, hope it helps, feel free to ask if you find anything difficult – Code Maniac 15 hours ago
  • Thanks for the comments! One last question, how do you know when to use map() or reduce(), since they are roughly similar – Issaki 15 hours ago
  • 1
    @Issaki map is generally used when you want to make some sort of changes it each element and keep the number of elements still the same, with map you will always get final output as array of elements,whereas the reduce is more flexible you can take only the values you need in your output and in desired structure too – Code Maniac 15 hours ago
  • Oh I see! Thanks for the reply! Helps me to understand a lot more :) – Issaki 15 hours ago
1

You could first simplify your structure to [type, value] pairs. Then create a map keyed by type, with sets as values (to guarantee uniqueness of the values), populate that, and finally convert that map to the desired structure:

var items = [{attributes: [{type: "Size",value: "Small"},{type: "Color",value: "Black"}]},{attributes: [{type: "Size",value: "Small"},{type: "Color",value: "White"}]},{attributes: [{type: "Size",value: "Medium"},{type: "Color",value: "Black"}]},{attributes: [{type: "Size",value: "Medium"},{type: "Color",value: "White"}]}];

const pairs = items.flatMap(({attributes}) => attributes.map(({type, value}) => [type, value]));
const map = new Map(pairs.map(([type]) => [type, new Set]));
pairs.forEach(([type, value]) => map.get(type).add(value));
const result = Array.from(map, ([type, values]) => ({ type, values: [...values] }));

console.log(result);

1

var items = [
  {
    attributes: [
      {
        type: "Size",
        value: "Small"
      },
      {
        type: "Color",
        value: "Black"
      }
    ]
  },
  {
    attributes: [
      {
        type: "Size",
        value: "Small"
      },
      {
        type: "Color",
        value: "White"
      }
    ]
  },
  {
    attributes: [
      {
        type: "Size",
        value: "Medium"
      },
      {
        type: "Color",
        value: "Black"
      }
    ]
  },
  {
    attributes: [
      {
        type: "Size",
        value: "Medium"
      },
      {
        type: "Color",
        value: "White"
      }
    ]
  }
];



var temp={};  // temporarly holder

items.forEach(function(item){  // iterate through each element
   item.attributes.forEach(function(attr){  // iterate through attributes of each element
   
    if (!temp[attr.type]) { temp[attr.type] = []; }  // if this is the first time we encounter
                                                       // this attribute, create a new placeholder
                                                       
    if(temp[attr.type].indexOf(attr.value)<0) {   // only add the attribute value if it was
                                                   // not added before
            temp[attr.type].push(attr.value);
    };
   });
});

var result = [];  // create the output result array

Object.keys(temp).forEach(function(key){  // iterate thought the keys of the temp object
  // add a new element with the properties congigured as desired
  result.push({type:key, values:temp[key]});
  
});

console.log(result);

1

var items = [
  {
    attributes: [
      {
        type: "Size",
        value: "Small"
      },
      {
        type: "Color",
        value: "Black"
      }
    ]
  },
  {
    attributes: [
      {
        type: "Size",
        value: "Small"
      },
      {
        type: "Color",
        value: "White"
      }
    ]
  },
  {
    attributes: [
      {
        type: "Size",
        value: "Medium"
      },
      {
        type: "Color",
        value: "Black"
      }
    ]
  },
  {
    attributes: [
      {
        type: "Size",
        value: "Medium"
      },
      {
        type: "Color",
        value: "White"
      }
    ]
  }
];

var results=[];
var type=[];
var values=[];

for(var i=0; i<items.length;i++){
  var x=items[i].attributes;
  for(var j=0; j<x.length;j++){
    var pos=type.indexOf(x[j].type);
    if(pos==-1){
      type.push(x[j].type);
      values.push([]);
      pos=type.length-1;
    }
    if(values[pos].indexOf(x[j].value)==-1) values[pos].push(x[j].value);
  }
}

for(var i=0; i<type.length;i++){
  results.push({type:type[i],values:values[i]})
}

console.log(results);

New contributor
Julian Vizcaino is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
1

You don't want to use map, you want to use a reduce.

items.reduce(
    (acc, item) => {

        item.attributes.forEach(
            attribute => {
                let type = acc.find(type => type.type == attribute.type);

                if (!type) {
                    type = {type: attribute.type, values: []};
                    acc.push(type);
                }       

                if (!type.values.includes(attribute.value)) {
                    type.values.push(attribute.value);
                }
            }
        );

        return acc;
    }, []
)
New contributor
JulianoLadeira is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
0

This will generate a slightly different output. An object instead of an array of objects.

let result = {};
items.forEach(item => item.attributes.forEach(att => { 
  if (result[att.type]) result[att.type].push(att.value);
  else result[att.type] = [att.value];
}));
  • Hi, thanks for the reply! But this is not the structure that I want. – Issaki 15 hours ago

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.