I have an array of objects that looks like this:
[
{"name":"Andrea","from":"USA","Food":"Candy"},
{"name":"Matt","from":"Taiwan","Food":"Chicken"},
{"name":"Roddy","from":"USA","Food":"Rice"},
{"name":"Andy","from":"Great Britain","Food":"Steak"},
];
Is there a way to get the list of all countries from the array above, and get rid of the repeated ones?
So from the list above, the list I am to obtain is:
["USA", "Taiwan", "Great Britain"]
Thank you!
Just loop over people and insert unique countries in a new array. Here is an example.
var countries = [];
var people = [
{"name":"Andrea","from":"USA","Food":"Candy"},
{"name":"Matt","from":"Taiwan","Food":"Chicken"},
{"name":"Roddy","from":"USA","Food":"Rice"},
{"name":"Andy","from":"Great Britain","Food":"Steak"},
];
for (var i = 0, l=people.length; i < l; i++) {
if(people[i] && people[i].from) {//ensure country exists
if (countries.indexOf(people[i].from) == -1) {//ensure unique
countries.push(people[i].from);
}
}
}
Yet another variant with reduce
var arr = [
{"name":"Andrea","from":"USA","Food":"Candy"},
{"name":"Matt","from":"Taiwan","Food":"Chicken"},
{"name":"Roddy","from":"USA","Food":"Rice"},
{"name":"Andy","from":"Great Britain","Food":"Steak"},
];
var countries = arr.reduce(function(acc, cur){
if(!acc.map[cur.from]){
acc.map[cur.from]=true;
acc.result.push(cur.from);
}
return acc;
}, {result:[], map:{}}).result;
var arr = [
{"name":"Andrea","from":"USA","Food":"Candy"},
{"name":"Matt","from":"Taiwan","Food":"Chicken"},
{"name":"Roddy","from":"USA","Food":"Rice"},
{"name":"Andy","from":"Great Britain","Food":"Steak"},
];
var countries = arr.reduce(function(acc, cur){
if(!acc.map[cur.from]){
acc.map[cur.from]=true;
acc.result.push(cur.from);
}
return acc;
}, {result:[], map:{}}).result;
document.getElementById('countries').innerHTML = countries.join();
<span id="countries"></span>
If you are already using the excellent Lodash library, the following will do it for you neatly in one line:
var uniqueCountries = _(dataArray).pluck('from').unique().value();
UnderscoreJS has similar functionality using chaining.
For D3.js, the following will do it:
var uniqueCountries = d3.set(dataArray.map(function (x) { return x.from; })).values();
Without doing the unique-ifying on the server and returning that data separately, there is no way to get around looping through all records at least once to do this. For 1000 records or so, though, this will still be very fast.
For plain JS, see other answers.
I'd loop over the Array and put the country into an array if it is not yet inside that array.
Related
I have arrays like this,
0: {"pure_id":"1","branch_id":"45"}
1: {"pure_id":"2","branch_id":"45"}
2: {"pure_id":"3","branch_id":"45"}
3: {"pure_id":"3","branch_id":"45"}
I am looking to group the above arrays into a single array based on pure_id, so the result array will be this below, and the index will be pure_id index
1: [{"pure_id":"1","branch_id":"45"}]
2: [{"pure_id":"2","branch_id":"45"}]
3: [{"pure_id":"3","branch_id":"45"},{"pure_id":"3","branch_id":"45"}]
I am trying lots of things honestly, but I cannot make it work.
Please help.
const result = [];
for(const el of array)
(result[el.pure_id] || (result[el.pure_id] = [])).push(el);
Using the new object literal rest and spread syntax, the property expression syntax, and .reduce() makes this pretty short and simple.
var arr = [
{"pure_id":"1","branch_id":"45"},
{"pure_id":"2","branch_id":"45"},
{"pure_id":"3","branch_id":"45"},
{"pure_id":"3","branch_id":"45"}
];
var result = arr.reduce((res, {pure_id, ...props}) =>
({...res, [pure_id]: (res[pure_id] || []).concat({pure_id, ...props})})
, {});
console.log(result);
The .reduce() is of course just creating a new object. Each iteration takes the accumulated properties and adds them to an object literal, but with the pure_id being the concatenation of the properties of the current object (copy) to an array.
I often see people struggle with something in programming that outside of it would not be a problem. Instead of arrays and objects, you can think of it as fruit.
Imagine a bucket of fruit. You want to sort the one bucket of fruit into 1 bucket for each color of fruit (color just being a property of a piece of fruit). So you would:
grab one fruit at a time
figure out it's color
if there is no bucket for that color, get one
put the fruit in the proper bucket
repeat until there are no fruits left
What we created was an algorithm for sorting fruit by color. The problem you are solving is very similar. In pseudocode it would be:
for each fruit
color = fruit.color
if not bucket[color]
make bucket[color]
put fruit in bucket[color]
to translate that to JS
var fruits = [
{color: "red"},
{color: "orange"},
{color: "pink"},
{color: "red"}
];
var buckets = {};
for (var i=0; i<fruits.length; i++) {
var fruit = fruits[i];
var color = fruit.color;
if (!buckets[color])
buckets[color] = [];
buckets[color].push(fruit);
}
So now, if you want to work with your array, the algorithm stays the same you just swap out the parts.
var things = [
{"pure_id":"1","branch_id":"45"},
{"pure_id":"2","branch_id":"45"},
{"pure_id":"3","branch_id":"45"},
{"pure_id":"3","branch_id":"45"}
];
var grouped = [];
for (let i=0; i<things.length; i++) {
var thing = things[i];
var id = thing['pure_id'];
if (!grouped[id])
grouped[id] = [];
grouped[id].push(thing);
}
console.log(grouped)
So, here we are at the first solution. It works! There are better solutions (using reduce, forEach or others) but don't let data structures like arrays or dictionaries scare you away. Think about it in simpler terms if it helps.
If don't use reduce, the codes will be like below:
Assuming your expected result is one array like:
[[{'pure_id':0, 'branch_id':1}], [{'pure_id':1, 'branch_id':2}]]
//assuming your array is like below:
var test = [{"pure_id":"1","branch_id":"43"},
{"pure_id":"2","branch_id":"44"},
{"pure_id":"3","branch_id":"45"},
{"pure_id":"3","branch_id":"46"}]
var result = []
var index_db = {} //use dict to save the mapping between the index of result and pure_id
var index = 0
test.forEach(function(item){
if(item.pure_id in index_db){
result[index_db[item.pure_id]].push(item)
}
else{
result.push([item])
index_db[item.pure_id] = index++
}
});
console.log(result)
Below is one reduce version:
//assuming your array is like below:
var test = [{"pure_id":"1","branch_id":"43"},
{"pure_id":"2","branch_id":"44"},
{"pure_id":"3","branch_id":"45"},
{"pure_id":"3","branch_id":"46"}]
result = test.reduce(function(pre, cur){
if(cur['pure_id'] in pre['indexes']){
pre['result'][pre['indexes'][cur['pure_id']]].push(cur)
}
else{
pre['result'].push([cur])
pre['indexes'][cur['pure_id']] = pre['pos']++
}
return pre
}, {'pos':0, 'indexes':{}, 'result':[]})
console.log(result['result'])
This is my array:
var country = ["US(+1)","IND(+91)"];
And i want to convert my array in this below format:
country = [
{
title: "US(+1)",
},
{
title: "IND(+91)",
}
]
word title should be same for each array value.
with this code am trying to get my expected result as above
var obj = country.reduce(function(o, val) { o['title'][] = val; return o; }, {});
But my output is comes like this as below: only last index is taking place
{"title":"IND(+91)"} this is wrong output which i dont want
You may be able to do it with reduce but it's much easier to use map:
var country = ["US(+1)","IND(+91)"];
var obj = country.map(function(c){return {title:c}});
console.log("country:", country);
console.log("obj:", obj);
map is for when you want to turn an array of things into another array of things, and reduce is when you want to turn an array of things into just a single thing.
var country = ["US(+1)","IND(+91)"];
I would use a more descriptive word since it is a list of countries.
var countries = ["US(+1)","IND(+91)"];
But to answer your question, to manipulate an array into a new array, I like to use the array.map method:
var objects = countries.map(function(country){ return { title: country } });
Here is the documentation for map:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map?v=control
I'm trying to populate a tree component using angularjs via this JSON object:
var myData=[{"agence":"CTM","secteur":"Safi","serie":"CZC1448YZN"},{"agence":"CTM","secteur":"Safi","serie":"2UA13817KT"},{"agence":"CTM","secteur":"Rabat","serie":"CZC1349G1B"},{"agence":"CTM","secteur":"Rabat","serie":" 2UA0490SVR"},{"agence":"CTM","secteur":"Agdal","serie":" G3M4NOJ"},{"agence":"CTM","secteur":"Essaouira","serie":" CZC1221B85"},{"agence":"Gare Routiere Municipale","secteur":"Essaouira","serie":" CZC145YL3"}] ;
heres the javascript code :
var treedata_avm = [];
for(var i=0; i < myData.length; i++) {
// alert('roro '+myData[i].secteur);
treedata_avm.push({
label: myData[i].secteur,
children: [{
label: myData.agence,
children: [myData[i].serie]
}]
});
}
$scope.my_data = treedata_avm;
HTML:
<abn-tree tree-data="my_data " tree-control="my_tree" on-select="my_tree_handler(branch)" expand-level="2" initial-selection="Granny Smith" icon-leaf="ti-file" icon-expand="ti-plus" icon-collapse="ti-minus"></abn-tree>
it works fine but i didnt get the expected bevaviour which i want..what i want is to get the data group by secteur and agence like this:
-Safi
-CTM
CZC1448YZN
2UA13817KT
-Rabat
-CTM
CZC1349G1B
2UA0490SVR
-Agdal
G3M4NOJ
-Essaouira
-CTM
CZC1221B85
-Gare Routiere Municipale
CZC145YL3
You could use groupBy() to initialize the structure as you want:
myData = _.groupBy(this.myData, 'secteur');
But then you'd have to add in the appropriate extras (agence, serie etc) to each object.
Or you could use _.reduce() which would combine the two (which would probably be better for you). Remember that reduce() is also a method on arrays in Plain Ol' JavaScript so you're not forced to use lodash:
_.reduce(this.myData, function(acc, value, key) {
(result[key] || result[key] = value).push(acc);
return acc;
}, acc);
I got a json array like below:
[
{"value":"uk-icon-adjust","title":"Adjust","url":"#", "text":""},
{"value":"uk-icon-adn","title":"Adn","url":"#", "text":""},
{"value":"uk-icon-align-center","title":"Align center","url":"#", "text":""},
{"value":"uk-icon-align-justify","title":"Align justify","url":"#", "text":""},
{"value":"uk-icon-align-left","title":"Align left","url":"#", "text":""}
]
I want to search this json array for specific titles. But the problem is, that I want to search with a Regex.
e.g: sb searchs for "ad" -> the function should return the first two json strings (Adjust and Adn).
I have no idea, now to setup a javascript function which can achieve this.
Some ideas?
Try this:
var array = [
{"value":"uk-icon-adjust","title":"Adjust","url":"#", "text":""},
{"value":"uk-icon-adn","title":"Adn","url":"#", "text":""},
{"value":"uk-icon-align-center","title":"Align center","url":"#", "text":""},
{"value":"uk-icon-align-justify","title":"Align justify","url":"#", "text":""},
{"value":"uk-icon-align-left","title":"Align left","url":"#", "text":""}
],
searchString = 'ad',
searchRegExp = new RegExp(searchString , 'i'); // 'i' makes the RegExp ignore case
var result = array.filter(function(e){ // Filter out any items that don't pass the
return searchRegExp.test(e.title); // RegExp test.
});
Result:
[
{"value":"uk-icon-adjust","title":"Adjust","url":"#","text":""},
{"value":"uk-icon-adn","title":"Adn","url":"#","text":""}
]
If you only want an array of titles, you can then map the result, like this:
var titles = result.map(function(e){
return e.title;
});
Titles:
["Adjust", "Adn"]
You'll want to do this mapping after filtering the array, for efficiency. This way you'll only have to iterate over the filtered result, instead of first iterating over all items to get the titles, then iterating over all of them again to filter them.
Of course, this can be combined with the filtering:
var result = array.filter(function(e){
return searchRegExp.test(e.title);
}).map(function(e){
return e.title;
});
Please keep in mind that both Array.prototype.filter() as Array.prototype.map() Aren't supported in IE 8 or lower. However, the pages I linked to do have some polyfills to make these functions work in older versions of IE.
That's an native Object. You can do it this way though, by first creating an Array of titles by using Array.map and then filter them using Array.filter
var titles = obj.filter(function(o){
return /^ad/i.test(o.title);
}).map(function(o){ return o.title; });
Amit Joki answer is the answer.
If you don't want to use map(), you could also try:
var json = [
{"value":"uk-icon-adjust","title":"Adjust","url":"#", "text":""},
{"value":"uk-icon-adn","title":"Adn","url":"#", "text":""},
{"value":"uk-icon-align-center","title":"Align center","url":"#", "text":""},
{"value":"uk-icon-align-justify","title":"Align justify","url":"#", "text":""},
{"value":"uk-icon-align-left","title":"Align left","url":"#", "text":""}
];
function search(array, re) {
var regexp = new RegExp(re, 'gi');
for (var i = 0; i < array.length; i++) {
return array[i].title.match(regexp);
}
throw "Couldn't find object like " + re;
}
console.info(search(json, 'ad'));
I have an array like this (with just over 3000 objects instead of the 3 here):
items = [{name:'charlie', age:'16'}, {name:'ben', age:'18'}, {name:'steve', age:'18'}]
What's the best way to return an array with just the objects of people who are 18? So I want:
items = [{name:'ben', age:'18'}, {name:'steve', age:'18'}]
The best I can think of is this (using jQuery):
newArray = []
$.each(items, function(index, item) {
if(item.age=='18') {
newArray.push(item)
}
})
Considering that there's 3000 thousand objects, and also that I'll be doing that comparison up to fifty times in one go, that's a lot of looping. Is there a better way?
You can use pure javascript
var wanted = items.filter( function(item){return (item.age==18);} );
And if your browser does not support the 1.6 version of javascript you can find an implementation of the filter method at https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/filter
Update
Speedwise there is a huge varying (had an error in the test) difference from a normal loop (depending on browser).. Have a look at this little test i made at http://jsperf.com/array-filter-vs-loop/3
Get matched item and items using find() and filter() method
If you want first matched single item, use find() method which returns single object.
If you want all matched , use filter() method which returns array of objects.
let items = [{name:'charlie', age:'16'},
{name:'ben', age:'18'},
{name:'steve', age:'18'}]
let all = items.filter(item=> item.age==='18')
console.log(all);
let single = items.find(item=> item.age==='18')
console.log(single);
If you're going to do the search often it may be best to keep a version of your data in a form that is quick to access.
I've used underscore.js (http://documentcloud.github.com/underscore/) to make it easy for myself, but this code here will create an object that holds your data indexed by the age field.
You end up with something that looks like this:
{
"16": [
{
"name": "charlie",
"age": "16"
}
],
"18": [
{
"name": "ben",
"age": "18"
},
{
"name": "steve",
"age": "18"
}
]
}
The code:
var itemsByAge = _(items).reduce(function(memo, item) {
memo[item.age] = memo[item.age] || [];
memo[item.age].push(item);
return memo;
}, {});
alert(JSON.stringify(itemsByAge["18"]));
No matter which method you choose (items.filter or any "query language" for json), a for loop is inevitable.
If performance is a concern, I would recommend you to use pure javascript instead of libraries like jQuery which will add overheads to the whole processing as is evident here.
Thus, your code would look like:
var newArray = [];
for(var i=0;i<items.length;i++) {
var item = items[i];
if(item.age == '18') {
newArray.push(item);
}
});
making use of javascript magnificent function eval() which evaluates string as code at runtime, we can define a prototype method for Array type
Array.prototype.where = function (query) {
var newArray = [];
for(var i=0; i<this.length; i++) {
var item = this[i];
if(eval( "item" + query )) {
newArray.push(item);
}
}
return newArray;
};
and use it with any array, passing the query as string
var newArray= items.where('.age >= 18');
Use the filter method of the array, it calls the provided callbackfunction once for each element in an array.
array.filter(<callbackfucntion>[, <Object to use>])
once i had such problem and i solved it like this
1- create an array of array
2- each index create an Index record
e.g.
var pAry=[];
var cAry=[{name:'ben', age:'18'}, {name:'steve', age:'18'}]
pAry[17]=cAry;
This way when u require person with age 18, you will get on index 17.