I have a JSON object as follows:
var testJSON = [
{ "AssetA": "asset_a", "AssetB": "asset_b" },
{ "AssetA": "asset_a", "AssetB": "asset_b" },
{ "AssetA": "asset_c", "AssetB": "asset_d" },
{ "AssetA": "asset_c", "AssetB": "asset_e" }];
What I want to do is step through the object and add repeating keys to another array, usedAssets. Here is my code so far:
var usedAssets = [];
for (var key in testJSON) {
console.log("Current key: " + key + " " + "value: : " + testJSON[key].AssetA);
console.log("Current key: " + key + " " + "value: : " + testJSON[key].AssetB);
// check if in array
if ((isInArray(testJSON[key].AssetA, usedAssets) || isInArray(testJSON[key].AssetB, usedAssets))) {
break;
}
else {
usedAssets.push(testJSON[key].AssetA);
usedAssets.push(testJSON[key].AssetB);
}
}
console.log(usedAssets);
function isInArray(value, array) {
return array.indexOf(value) > -1;
}
However, my output of that is just an array with asset_a and asset_b. The usedAssets array should contain asset_a, asset_b, and asset_c. My end goal is to be able to determine at the end of the iteration, that I used asset_a only once, asset_b only once, and asset_c only once.
3 Answers 3
Basically, you could iterate all elements of the array and all properties of the object and count the occurence.
var testJSON = [{ "AssetA": "asset_a", "AssetB": "asset_b" }, { "AssetA": "asset_a", "AssetB": "asset_b" }, { "AssetA": "asset_c", "AssetB": "asset_d" }, { "AssetA": "asset_c", "AssetB": "asset_e" }],
count = {};
testJSON.forEach(o => Object.keys(o).forEach(k => count[o[k]] = (count[o[k]] || 0) + 1));
console.log(count);
console.log(Object.keys(count).filter(k => count[k] > 1));
.as-console-wrapper { max-height: 100% !important; top: 0; }
ES5
var testJSON = [{ "AssetA": "asset_a", "AssetB": "asset_b" }, { "AssetA": "asset_a", "AssetB": "asset_b" }, { "AssetA": "asset_c", "AssetB": "asset_d" }, { "AssetA": "asset_c", "AssetB": "asset_e" }],
count = {};
testJSON.forEach(function (o) {
Object.keys(o).forEach(function (k) {
count[o[k]] = (count[o[k]] || 0) + 1;
});
});
console.log(count);
console.log(Object.keys(count).filter(function (k) {
return count[k] > 1;
}));
.as-console-wrapper { max-height: 100% !important; top: 0; }
4 Comments
This snippet takes your array and reduces it to the seen values.
var testJSON = [
{ "AssetA": "asset_a", "AssetB": "asset_b" },
{ "AssetA": "asset_a", "AssetB": "asset_b" },
{ "AssetA": "asset_c", "AssetB": "asset_d" },
{ "AssetA": "asset_c", "AssetB": "asset_e" }];
var seen = {};
var result = testJSON.map(function(value){
return Object.keys(value).map(function(key){
return value[key];
})
}).reduce(function(a, b) {
return a.concat(b);
}, []).filter(function(value){
if (!seen[value]){
seen[value] = 1;
return true;
}
seen[value] += 1;
return false;
})
// seen contains the number of times each value was 'seen'
console.log('seen: ' + JSON.stringify(seen));
console.log('result: ' + result);
Comments
It sounds like you're trying to count how many times each asset was used... The simplest way is to keep a map of objects you have seen before. Array.prototype.reduce is a nice way to do that
var testJSON = [{"AssetA":"asset_a","AssetB":"asset_b"},{"AssetA":"asset_a","AssetB":"asset_b"},{"AssetA":"asset_c","AssetB":"asset_d"},{"AssetA":"asset_c","AssetB":"asset_e"}];
var usage = testJSON.reduce((prev, next) => {
prev[next.AssetA] = next.AssetA in prev ? prev[next.AssetA] + 1 : 1;
prev[next.AssetB] = next.AssetB in prev ? prev[next.AssetB] + 1 : 1;
return prev;
}, {});
console.log('How much were they used?', usage);
// If you want to know which ones were used two or more times, you can use
console.log('Used more than once', Object.keys(usage).filter(key => usage[key] > 1))
A version of the above without reduce would be
var usage = {};
testJSON.forEach(el => {
usage[el.AssetA] = el.AssetA in usage ? usage[el.AssetA] + 1 : 1;
usage[el.AssetB] = el.AssetB in usage ? usage[el.AssetB] + 1 : 1;
});
console.log('How much were they used?', usage);
// If you want to know which ones were used two or more times, you can use
console.log('Used more than once', Object.keys(usage).filter(key => usage[key] > 1))
7 Comments
[1,2,3,4].reduce( (prev, next) => prev + next, 0). That will add all the items in the array, giving it a 0 as the starting value for the calculations. In my example, the starting value is an object that will be used as the map, and we iterate over the array, stuffing the object for each element in the array
asset_d?