Number of objects with distinct property in a list - javascript

Here is a simple data set
data = [
{'artist':'a','song':'a'},
{'artist':'a','song':'b'},
{'artist':'a','song':'c'},
{'artist':'b','song':'d'},
{'artist':'b','song':'e'},
{'artist':'c','song':'f'},
{'artist':'d','song':'g'},
{'artist':'d','song':'h'},
{'artist':'d','song':'i'}
];
Is there any native function in javascript or jQuery that would allow me to get the number of disctinct artist in a concise expression ?

To get the number of distinct artists you can use this:
Object.keys(data.reduce(function(p, c) { p[c.artist] = 1 ; return p }, {})).length
this being a one liner that accumulates the distinct values of c.artist in the object p, then counts how many keys there are.

You may try like this:
var array = [{"artist":"a","song":"a"}, {"artist":"a","song":"b"}, {"artist":"a","song":"c"}]
var unique = {};
var distinct = [];
for( var i in array ){
if( typeof(unique[array[i].song]) == "undefined"){
distinct.push(array[i].song);
}
unique[array[i].song] = 0;
}
var d = document.getElementById("d");
d.innerHTML = "" + distinct;
JSFIDDLE DEMO

try this, DEMO here
data = [
{'artist':'a','song':'a'},
{'artist':'a','song':'b'},
{'artist':'a','song':'c'},
{'artist':'b','song':'d'},
{'artist':'b','song':'e'},
{'artist':'c','song':'f'},
{'artist':'d','song':'g'},
{'artist':'d','song':'h'},
{'artist':'d','song':'i'}
];
newdata=[];
$.each(data, function(index,value){
newdata[index]=data[index].artist;
});
alert($.unique(newdata));

Related

Remove Duplicate elements from Array - Javascript (No JQuery & ECMAScript)

Case: We have 'n' number of arrays stored in an array (Array of Arrays). Now that each child array in this parent array can have elements that may or may not be present in other child arrays. Output - I need to create an array which has the all the elements present in all the child arrays excluding the duplicates.
I do not want to concatenate all the arrays into a single array and use unique method to filter out. I need to create unique array then and there during iteration.
Ex:
var a[] = [1,2,3,4,5];
var b[] = [1,2,7,8];
var c[] = [1,2,3,4,5,6,7,8];
var d[] = [9,10,11,12];
var arr[] = [a,b,c,d]
Output must be [1,2,3,4,5,6,7,8,9,10,11,12]
P.S: I can concat the arrays and use jquery unique function to resolve this, but i need a solution in javascript alone. Thanks
You can use array#reduce to flatten your array and then use Set to get distinct values and use array#from to get back array from Set.
var a = [1,2,3,4,5];
var b = [1,2,7,8];
var c = [1,2,3,4,5,6,7,8];
var d = [9,10,11,12];
var arr = [a,b,c,d]
var result = Array.from(new Set(arr.reduce((r,a) => r.concat(a))));
console.log(result);
Try using .filter when adding each array to the final one, filtering out the duplicates:
a.filter(function(item) {
return !finalArray.contains(item));
});
Answer using Sets:
var a = [1,2,3,4,5];
var b = [1,2,7,8];
var c = [1,2,3,4,5,6,7,8];
var d = [9,10,11,12];
var concat = a.concat(b).concat(c).concat(d);
var union = new Set(concat);
//console.log(union);
ES6 Answer:
let a = new Set([1,2,3,4,5]);
let b = new Set([1,2,7,8]);
let c = new Set([1,2,3,4,5,6,7,8]);
let d = new Set([9,10,11,12]);
let arr = new Set([...a,...b,...c,...d]);
//Result in arr.
Whats going on???
From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set:
The Set object lets you store unique values of any type, whether
primitive values or object references.
So when we initialise Sets passing arrays to the constructor we basically ensure that there are no duplicate values.
Then in the last line, we concat all the Sets we initialised prior into a final set.
The ... notation converts the Set into an array, and when we pass the 4 arrays to the constructor of the Set they get concatenated and a Set of their unique values is created.
Here is a functional alternative written in ES5.
var flatten = function(list) {
return list.reduce(function(acc, next) {
return acc.concat(Array.isArray(next) ? flatten(next) : next);
}, []);
};
var unique = function(list) {
return list.filter(function(element, index) {
return list.indexOf(element) === index;
})
}
var a = [1,2,3,4,5];
var b = [1,2,7,8];
var c = [1,2,3,4,5,6,7,8];
var d = [9,10,11,12];
var arr = [a,b,c,d];
var result = unique(flatten(arr));
console.log(result);
If you support ES6, arrow function can make that code even shorter.
Here is a solution that uses a plain object for resolving duplicates, and only uses basic ES3 JavaScript. Runs in IE 5.5 and higher, and with O(n) time complexity.
function uniques(arr) {
var obj = {}, result = [];
for (var i = 0; i < arr.length; i++) {
obj[arr[i]] = true;
}
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) result.push(+prop);
}
return result;
}
// Example use
var a = [1,2,3,4,5],
b = [1,2,7,8],
c = [1,2,3,4,5,6,7,8],
d = [9,10,11,12];
var result = uniques(a.concat(b, c, d));
console.log('Result: ' + result);
As an object can only have a unique set of properties (no duplicates), the use of all array values as properties in an object will give you an object with a property for each unique value. This happens in the first loop. NB: the value given to those properties is not relevant; I have used true.
Then the result is just the conversion of those properties back to array values. This happens in the second loop.
var a = [1,2,3,4,5];
var b = [1,2,7,8];
var c = [1,2,3,4,5,6,7,8];
var d = [9,10,11,12];
var result = a.concat(b,c,d);
function remvDup(result){
var tmp = [];
for(var i = 0; i < result.length; i++){
if(tmp.indexOf(result[i]) == -1){
tmp.push(result[i]);
}
}
return tmp;
}
console.log(remvDup(result));
Becuase the OP mentioned that he cannot use 'Set' as it is not supported on the targeted browsers, I would recommand using the 'union' function from the lodash library.
See union's documentation here

How do I search a string in JavaScript array using jQuery? [duplicate]

This question already has answers here:
How can I access and process nested objects, arrays, or JSON?
(31 answers)
Closed 6 years ago.
I have a JavaScript array:
var j_array = new Array();
j_arry=["class:1","division:a","class:5","class:3","division:b","division:c","division:d","class:10"];
I need to find how many times the class is coming and its array key, so I use:
found = $.inArray('class', j_array); ` But it returns `-1`;
Then I use:
var search = 'class';
$.each([j_array], function(index, value){
$.each(value, function(key, cell){
if (search.indexOf(cell) !== -1)
console.log('found in array '+index, cell);
});
});
But that is also wrong. How do I solve this?
From this array I want to get the following:
Class coming 4 times, at key 0, 2, 3, and 7
I want to make a separate array of class only, that is,
new_array = ["class:1", "class:2", "class:3", "class:10"];
Currently there are four classes in j_array. How can I get the Nth class value
That is, 1st class value ="class:1", 2nd class value="class:5", etc.
You could filter elements which match in a new array and just return the length of this new array
var j_arry = ["class:1","division:a","class:5","class:3","division:b","division:c","division:d","class:10"];
var res = j_arry.filter(x => x.includes("class"));
var key = res.map(x => x.split(":")[1]);
console.log("Class coming " + res.length + " , at key " + key.join(","));
console.log("new array = ", res);
Use Array.prototype.filter to filter out the elements of the array that contains the string class - see demo below:
var j_array =["class:1","division:a","class:5","class:3","division:b","division:c","division:d","class:10"];
var result = j_array.filter(function(e){
return e.indexOf('class')!==-1;
});
console.log(result);
EDIT:
To get the list of indexes too, you can try this:
var j_array =["class:1","division:a","class:5","class:3","division:b","division:c","division:d","class:10"];
var filteredIndices = []
var filtered = j_array.filter(function(e,i){
if(e.indexOf('class')!==-1) {
filteredIndices.push(i);
return true;
} else {
return false;
}
});
console.log(filtered);
console.log(filteredIndices);
// Nth class value
console.log(filtered[2]); // this prints the 3rd one
.as-console-wrapper{top:0;max-height:100%!important;}
Here is the answer to your questions 1 + 2. It is also 'n' proof so answers your part 3 also. This works by old-fashioned hard graft rather than funky functions. The original array entries are split and filtered then if qualifying we store in an associative array (results) using a pointer array (list) to make it easier to give a sorted result and pull the values from the associative array. The max variable is probably not necessary but included for clarity - could have used list.length instead. Note that the list[] array will be sparse (missing steps) so we test each entry before use in the output steps.
var j_array = new Array();
j_arry=["class:1","division:a","class:5","class:3","division:b","division:c","division:d","class:10","class:1"];
var a, result = [], list=[], max = -1
for (var i =0; i < j_arry.length; i = i + 1) {
var a = j_arry[i].split(":")
if ( a[0] === "class") {
var key = "c" + a[1]
if ( !result[key] ) { result[key] = {pos:[]}}
result[key].cnt = result[key].cnt ? result[key].cnt + 1 : 1;
result[key].pos.push(i)
list[parseInt(a[1])] = "c" + a[1]
max = parseInt(a[1]) > max ? a[1] : max;
}
}
// say locations
for (var i = 0; i < max; i = i + 1) {
if (list[i]) {
key = "c" + i
console.log("Class " + i + " occurs at " + result[key].pos.toString() )
}
}
// make new array
var newArray=[]
for (var i = 0; i < max; i = i + 1) {
if (list[i]) {
newArray.push("Class:" + i)
}
}
console.log("New array=" + newArray.toString() )
Results are:
Class 1 occurs at 0,8
Class 3 occurs at 3
Class 5 occurs at 2
New array=Class:1,Class:3,Class:5
Single reduce is sufficient here.
var arr = ["class:1","division:a","class:5","class:3","division:b","division:c","division:d","class:10"],
res = arr.reduce((p,c) => c.includes("class") ? (p.count++, p.keys.push(c.split(":")[1]), p)
: p ,{count:0, keys:[]});
console.log(res);
You can use the filter and map functions to filter your array to have only elements that match the text 'class', and use array index notation to access the nth element in the array. Check the below code snippet I hope it will be of help to you.
The below code snippet uses ES6 arrow syntax.
var arr = ["class:1", "division:a", "class:5", "class:3", "division:b", "division:c", "division:d", "class:10"];
var result = arr.filter(x => x.indexOf('class') !== -1);
var indices = result.map(x => arr.indexOf(x));
console.log(indices);
console.log(result);
var nValue = window.prompt('Enter n value');
console.log(result[nValue]);
If you're using jQuery to support some really old browser that still don't implement the new Array functions, and you don't want to polyfill those because you're already using jQuery, then you can use the jQuery equivalents:
var arr = ["class:1", "division:a", "class:5", "class:3", "division:b", "division:c", "division:d", "class:10"]
var result = $.grep(arr, function (x) { return x.indexOf('class') !== -1 })
var indices = $.map(result, function (x) { return arr.indexOf(x) })
This is the same code as this answer, but using jQuery.
You have to do map first then filter.
var j_array = ["class:1", "division:a", "class:5", "class:3", "division:b", "division:c", "division:d", "class:10"];
var result = j_array.map(function(e, i) {
return e.indexOf('class') > -1 ? '' + i : false;
}).filter(function(e) {
return !!e;
});
console.log(result);

Combining results into one object

I'm looping through a set of inputs. I need to tally up the grouped totals. The inputs below to one of three categories.
How do I go about combining the values up relevant to three categories?
var compoundedArray = new Array();
holder.find(".dataset input").each(function(index) {
var val = $(this).val();
var dataType = $(this).data("type");
var localObj = {};
localObj[dataType] = val;
compoundedArray.push(localObj);
});
I have an object like this
[
{
"growth":30
},
{
"growth": 40
},
{
"other": 20
}
]
how do I loop through the object to produce something like
[
{
"growth": 70
},
{
"other": 20
}
]
if I looped over the initial array object
for (var i = 0; i < compoundedArray.length; i++) {
console.log(compoundedArray[i]);
}
how would I go about checking to ensure I don't have duplicates - and that I can tally up the results?
Ideally the resulting format may be the best
var array = [
"matching": 50,
"growth": 20
]
var array = [
"matching": 50,
"growth": 20
]
is not valid JS, but you can create an object of the form
var obj = {
"matching": 50,
"growth": 20
};
And that's pretty easy to do, just use an object from the very beginning:
var result = {};
holder.find(".dataset input").each(function(index) {
var val = +$(this).val(); // use unary plus to convert to number
var dataType = $(this).data("type");
result[dataType] = (result[dataType] || 0) + val;
});
Further reading material:
MDN - Working with Objects
Eloquent JavaScript - Data structures: Objects and Arrays
You can just use an object (not array) with unique keys.
var compoundedObj = {};
$(".dataset input", holder).each(function() {
var dataType = $(this).data("type");
if(!compoundedObj.hasOwnProperty(dataType)) {
compoundedObj[dataType] = 0;
}
compoundedObj[dataType] += parseInt($(this).val(), 10);
});
In this way you'll get an object like this:
{
"growth": 70,
"other": 20
}
Live demo
http://jsfiddle.net/GFwGU/
var original = [{"growth":30},{"growth": 40},{"other": 20}]
// object to sum all parts by key
var sums = {}
// loop through original object
for(var index in original){
// get reference to array value (target object)
var outer = original[index]
// loop through keys of target object
for(var key in outer){
// get a reference to the value
var value = outer[key]
// set or add to the value on the sums object
sums[key] = sums[key] ? sums[key] + value : value
}
}
// create the output array
var updated = []
// loop through all the summed keys
for(var key in sums){
// get reference to value
var value = sums[key]
// create empty object
var dummy = {}
// build object into desired format
dummy[key] = value
// push to output array
updated.push(dummy)
}
// check the results
alert(JSON.stringify( updated ))
var add=function (a,b){ a=a||0; b=b||0; return a+b};
var input=[ {growth:30},{growth:40},{other:20} ],output=[],temp={};
$.each(input,function(i,o){
var n;
for(i in o)
{n=i;break}
temp[n]=add(temp[n],o[n]);
});
$.each(temp,function(i,o){
var k={};
k[i]=o;
output.push(k)
});

Create child objects from parent with same property values [duplicate]

This question already has answers here:
How to put items into grouped arrays where grouped by a particular key
(3 answers)
Closed 9 years ago.
I have a parent object. I want to create child objects from the parent with the same key value pair.
e.g.
parentJSON = {[name:"a1",address:"b1",comp:"c1"],
[name:"a2",address:"b2",comp:"c1"],
[name:"a3",address:"b3",comp:"c2"],
[name:"a4",address:"b4",comp:"c2"],
[name:"a5",address:"b5",comp:"c2"],
[name:"a6",address:"b6",comp:"c3"]}
Now I want to create child objects having same "comp" value.
e.g.
childJSON1 = {[name:"a1",address:"b1",comp:"c1"],
[name:"a2",address:"b2",comp:"c1"]}
childJSON2 = {[name:"a3",address:"b3",comp:"c2"],
[name:"a4",address:"b4",comp:"c2"],
[name:"a5",address:"b5",comp:"c2"]}
childJSON3 = {[name:"a6",address:"b6",comp:"c3"]}
This is what I tried to make it little bit (it will change the parent object with a key indicating number of repetition):
parentJSON = [1,2,3,3,4,4,4,5];
var i=0, x, count, item;
while(i < parentJSON.length) {
count = 1;
item = parentJSON[i];
x = i+1;
while(x < parentJSON.length &&
(x = parentJSON.indexOf(item, x)) != -1) {
count += 1;
parentJSON.splice(x,1);
}
parentJSON[i] = new Array(parentJSON[i],count);
++i;
}
console.log(parentJSON);`
first of all your json is in the incorrect format, it should look like this
[{name:"a1",address:"b1",comp:"c1"},
{name:"a2",address:"b2",comp:"c1"},
{name:"a3",address:"b3",comp:"c2"},
{name:"a4",address:"b4",comp:"c2"},
{name:"a5",address:"b5",comp:"c2"},
{name:"a6",address:"b6",comp:"c3"}]
An array of objects.
My attempt, also very readable.
var result = {};
$.each(parentJSON, function (i, item) {
if(!result[item.comp]) {
result[item.comp] = [];
}
(result[item.comp]).push(item);
});
alert(JSON.stringify(result))
JsFiddle
First of all your json is actually invalid. You may have an array of objects, but not object which contains an array like that. Also your arrays looks more like objects, because the syntax with the dots is used for objects. Here is how I guess should look like:
var parentJSON = [
[{name:"a1",address:"b1",comp:"c1"}],
[{name:"a2",address:"b2",comp:"c1"}],
[{name:"a3",address:"b3",comp:"c2"}],
[{name:"a4",address:"b4",comp:"c2"}],
[{name:"a5",address:"b5",comp:"c2"}],
[{name:"a6",address:"b6",comp:"c3"}]
];
var child1 = parentJSON.slice(0, 2);
var child2 = parentJSON.slice(2, 5);
And you may use the .slice method to get specific elements of the array.
So..you need to clone objects?
maybe tou can try sth like this:
var sergi= {
name: "sergi",
age: 33
};
var bill = (JSON.parse(JSON.stringify(sergi)));
bill.name = "Bill";
console.log(sergi);
console.log(bill);
parentJSON = function(){
return [
{name:"a1",address:"b1",comp:"c1"},
{name:"a2",address:"b2",comp:"c1"},
{name:"a3",address:"b3",comp:"c2"},
{name:"a4",address:"b4",comp:"c2"},
{name:"a5",address:"b5",comp:"c2"},
{name:"a6",address:"b6",comp:"c3"}
];
}
childJSON1 = new parentJSON().slice(0,2);
childJSON2 = new parentJSON().slice(2,5);
childJSON3 = new parentJSON().slice(5,6);
Try this:
DEMO
var data = [
[{name:"a1",address:"b1",comp:"c1"}],
[{name:"a2",address:"b2",comp:"c1"}],
[{name:"a3",address:"b3",comp:"c2"}],
[{name:"a4",address:"b4",comp:"c2"}],
[{name:"a5",address:"b5",comp:"c2"}],
[{name:"a6",address:"b6",comp:"c3"}]
];
var groups = {};
$.each(data, function(i, item) {
var comp = item.comp;
delete item.comp;
if(groups[comp]) {
groups[comp].push(item);
} else {
groups[comp] = [item];
}
});
var result = $.map(data, function(group, key) {
var obj = {};
obj[key] = group;
return obj;
});
alert(JSON.stringify(groups))

How to convert an array of objects into a mapped object in JavaScript?

How can I convert something like initialArray array of JSON objects into finalObject map?
var initialArray = [
{ id:'id1', name:'name1' },
{ id:'id2', name:'name2' },
{ id:'id3', name:'name3' },
{ id:'id4', name:'name4' }
];
var finalObject = {
'id1':'name1',
'id2':'name2',
'id3':'name3',
'id4':'name4'
}
Things to consider:
IDs are strings.
I tried for in loop - couldn't make it to work - http://jsfiddle.net/5af9R/23/
Any ideas?
You need to operate on the objects in your array, not strings containing their indexes in the array.
You should also use a regular for loop to iterate over an array.
Your JSFiddle, fixed:
var x = [ {id:'1', img:'img1'}, {id:'2', img:'img2'}, {id:'3', img:'img3'} ];
var resp = {};
for( var i = 0 ; i < x.length ; i++ ){
var obj = x[i];
resp[obj.id] = obj.img;
}
document.write( JSON.stringify(resp, undefined, 2) );
​
DEMO
You can loop over the array, and for each object, add a new property to finalObject whose property name is the id, and whose value is the name.
var finalObject = {};
for (var i = 0, max = initialArray.length; i < max; i++)
finalObject[initialArray[i].id] = initialArray[i].name;
resp[key.id] = key.img;
You correctly call it key. But you need a value;
resp[x[key].id] = x[key].img;
var finalObject = initialArray.reduce(function(ret, obj){
ret[obj.id] = obj.name;
return ret;
}, {});
This solution is specific to the property names for the specific question, but Array.prototype.reduce is a function I use all the time for any sort of array iteration that requires a non-array result.
You're not using For In correctly jsFiddle
var x = [ {id:'1', img:'img1'}, {id:'2', img:'img2'}, {id:'3', img:'img3'} ];
var resp = {};
for( var key in x ){
resp['id' + x[key].id] = x[key].img;
}
document.write( JSON.stringify(resp, undefined, 2) );
​
for (var i=0; i<x.length; i++) {
var id = 'id' + x[i].id;
var img = x[i].img;
resp[id] = img;
}
if i have understood correctly you can do something like
var x =' [ {"id":"1", "img":"img1"}, {"id":"2", "img":"img2"}, {"id":"3", "img":"img3"}]';
var resp = {};
var json = $.parseJSON(x);
$(json).each(function(i,v){
resp[v.id]=v.img;
});
console.log( resp);
DEMO
you talked about json but in the fiddle you provided there was no json even jquery was not added as a resource so i made some assumptions
Today I was on the same question and I didn't find an answer here, except the answer of #adam-rackis.
The way I found is :
var initialArray = [
{ id:'id1', name:'name1' },
{ id:'id2', name:'name2' },
{ id:'id3', name:'name3' },
{ id:'id4', name:'name4' }
],
finalObject = {};
$.each(initialArray, function(k,v) {
finalObject[v.name] = v.value;
});

Categories