3

I can't find a similar question and I'm a bit stuck. I have the following JSON array:

[
    {
        "Name": "element1",
        "Attributes": ["1", "2"]
    },

    {
        "Name": "element2",
        "Attributes": ["1","3" ]
    },
    {
        "Name": "element3",
        "Attributes": []
    }
]

I'm trying to create an array of all the unique elements in the "Attributes" property, but I'm having trouble looping through each object, and then looping through the array elements to return the unique values. I'm trying to do it with filter(), or map() preferably.

EDIT: I want an array of unique elements, so: [1,2,3].

Pranav C Balan
  • 113,687
  • 23
  • 165
  • 188
DorianHuxley
  • 642
  • 4
  • 10
  • 22

9 Answers9

2

You could do it with couple of Array methods. For example:

var result = [
    {
        "Name": "element1",
        "Attributes": ["1", "2"]
    },

    {
        "Name": "element2",
        "Attributes": ["1","3" ]
    },
    {
        "Name": "element3",
        "Attributes": []
    }
]

// map to [ ["1", "2"], ["1", "3"], [] ]
.map(item => item.Attributes)

// flatten to [ "1", "2", "1", "3" ]
.reduce((prev, curr) => prev.concat(curr), [])

// filter unique [ "1", "2", "3" ]
.filter((item, i, arr) => arr.indexOf(item) === i)

console.log(result)
dfsq
  • 191,768
  • 25
  • 236
  • 258
1

You can use Array#reduce and Array#filter methods

var data = [{
    "Name": "element1",
    "Attributes": ["1", "2"]
  },

  {
    "Name": "element2",
    "Attributes": ["1", "3"]
  }, {
    "Name": "element3",
    "Attributes": []
  }
]

console.log(
  // iterate over array elements
  data.reduce(function(arr, ele) {
    // push the unique values to array
    [].push.apply(arr,
      // filter out unique value
      ele.Attributes.filter(function(v) {
        // check element present in array
        return arr.indexOf(v) == -1;
      })
    );
    // return the unique array
    return arr;
    // set initial argument as an empty array
  }, [])
);

With ES6 arrow function

 var data = [{
     "Name": "element1",
     "Attributes": ["1", "2"]
   },

   {
     "Name": "element2",
     "Attributes": ["1", "3"]
   }, {
     "Name": "element3",
     "Attributes": []
   }
 ]

 console.log(
   data.reduce((arr, ele) => ([].push.apply(arr, ele.Attributes.filter((v) => arr.indexOf(v) == -1)), arr), [])
 );
Pranav C Balan
  • 113,687
  • 23
  • 165
  • 188
1

If lodash is an option, you can easily get what you want:

> _.chain(foo).map('Attributes').flatten().uniq().value()
["1", "2", "3"]
Mehraban
  • 3,164
  • 4
  • 37
  • 60
1
let uniqueSet = new Set()

let a = [
    {
        "Name": "element1",
        "Attributes": ["1", "2"]
    },

    {
        "Name": "element2",
        "Attributes": ["1","3" ]
    },
    {
        "Name": "element3",
        "Attributes": []
    }
]

for(let i=0; i<a.length; i++){
    a[i].Attributes.map((x) => uniqueSet.add(x))
}

console.log([...uniqueSet])
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Nov 03 '22 at 18:21
0
var uniqueArr = [];

var arr = [
    {
        "Name": "element1",
        "Attributes": ["1", "2"]
    },

    {
        "Name": "element2",
        "Attributes": ["1","3" ]
    },
    {
        "Name": "element3",
        "Attributes": []
    }
];

arr.forEach(function(obj) {
   var attr = obj.Attributes;
   attr.forEach(function(val){
       if (uniqueArray.indexOf(val) < 0) {
           uniqueArray.push(val)
       }
   });
})
Piyush.kapoor
  • 6,715
  • 1
  • 21
  • 21
0

You have answers to choose from. Just for fun: this one uses es6

"use strict";
let uniqueAttr = [];
const obj = [
    {
        "Name": "element1",
        "Attributes": ["1", "2"]
    },

    {
        "Name": "element2",
        "Attributes": ["1","3" ]
    },
    {
        "Name": "element3",
        "Attributes": []
    }
];

obj.forEach( element => 
  element.Attributes.forEach( 
    attr => uniqueAttr.indexOf(attr) < 0  && uniqueAttr.push(attr)
  ) 
);

document.querySelector("#result").textContent = uniqueAttr;
<pre id="result"></pre>
KooiInc
  • 119,216
  • 31
  • 141
  • 177
0

Try This, It'll help to solve this problem.

  var data = [{
    "Name": "element1",
    "Attributes": ["1", "2"]
  }, {
    "Name": "element2",
    "Attributes": ["1", "3"]
  }, {
    "Name": "element3",
    "Attributes": []
  }];
  var Attributes = [];
  $.each(data, function(i, e) {
    $.each(e.Attributes, function(i, e) {
      Attributes.push(parseInt(e));
    });
  });
  Attributes = $.unique(Attributes);
  alert(Attributes);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
Govind Samrow
  • 9,981
  • 13
  • 53
  • 90
0

With ES6/ES2015 you can use Set and the spread operator:

const input = [
    {
        "Name": "element1",
        "Attributes": ["1", "2"]
    },

    {
        "Name": "element2",
        "Attributes": ["1","3" ]
    },
    {
        "Name": "element3",
        "Attributes": []
    }
];

const output = [...new Set([].concat(...input.map(item => item.Attributes)))];

console.log(output);

Explanation (from the inside out):

  • input.map(item => item.Attributes) produces an array of the Attributes arrays
  • [].concat(...) flattens the arrays, i.e. produces an array of all the Attributes values (including duplicates)
  • new Set() produces a Set from the array, i.e. stores only the unique Attribute values
  • [...] produces an array from the Set's values, i.e. produces an array of all unique Attribute values
Daniel Rose
  • 17,233
  • 9
  • 65
  • 88
0

Building on top of @dfsq answer, you could replace the two map and reduce with a single flatMap

var result = [
    {
        "Name": "element1",
        "Attributes": ["1", "2"]
    },

    {
        "Name": "element2",
        "Attributes": ["1","3" ]
    },
    {
        "Name": "element3",
        "Attributes": []
    }
]

// map & flatten to [ "1", "2", "1", "3" ]
.flatMap(item => item.Attributes)

// filter unique [ "1", "2", "3" ]
.filter((item, i, arr) => arr.indexOf(item) === i)

console.log(result)
tsi
  • 1,244
  • 12
  • 10