I have an array of JSON-like object[Object,Object...] (I was calling it array of JSON object until I see this ) and I would like to go through each item in it. The JSON object has 3 values {name:"name",date:"2015-01-01",c:3} in it and I want to put each of them into a new array. Should I use a for item in JSONArary{item = ...} or for (i=0,i<len,i++){array[i] = ....} or should I JSONArray.pop()? Which one is faster and why? What if I want to reverse the array? Do reversing cost a lot?
for (i=0,i<len,i++){array[i] = ....} should be faster than for item in JSONArary{item = ...} because the later will traverse all enumerable properties on this object, while some of these properties are unnecessary.
When you want to iterate over just the indexed properties of an array, the only guaranteed way to keep things semantically consistent is to use an integer index.
For your reference: Why is using "for...in" with array iteration a bad idea?
Even Google make the JavaScript coding style guide as:
for-in loop: Only for iterating over keys in an object/map/hash
I have a faster way, use $.map:
var oldArray = [{
name: "name1",
date: "2015-01-01",
c: 3
}, {
name: "name2",
date: "2015-01-01",
c: 3
}, {
name: "name3",
date: "2015-01-01",
c: 3
}];
var newArray = $.map(oldArray, function (item) {
return {
FullName: item.name,
RegisterDate: item.date
};
});
alert(JSON.stringify(newArray));
Hope this help.
Related
In a few different places I've seen the following being used:
const arr = [
{ key: "someKey", value: 1 },
{ key: "anotherKey", value: true },
{ key: "yetAnotherOne", value: "hello world" },
];
To me, it seems more logical to use this structure:
const ob = {
someKey: 1,
anotherKey: true,
yetAnotherOne: "hello world",
};
Is there an advantage when using an array like this?
Arrays are explicitly ordered.
An array is typically used for a list of similar objects. Some advantages would be:
having a selection of array-specific methods to e.g. to filter/sort the objects
In an array of objects it would be possible to use the same key-property multiple times. In an object these would be overwritten.
That's all I could think of. Hope it's helpful ;).
That said I would normally recommend using an object if the above is not relevant.
In your example, it would be better to use the object because it means you can access the value of the property faster and easier using something like ob.anotherKey without having to use a loop or having to know the index in the array.
However, this might not always be the case...
Slightly different from the example above:
const people = [
{ firstName: "someKey", lastName: 1 },
{ firstName: "anotherKey", lastName: true },
{ firstName: "yetAnotherOne", lastName: "hello world" },
];
Is much easier to understand and a better representation of the data and than...
const people = {
someKey: 1,
anotherKey: true,
yetAnotherOne: "hello world",
};
This also requires previous knowledge that each key is the firstName and each value is the lastName.
I got a Javascript object which looks like this:
{
key1: {
itemId: "someId",
myValue: "value"
},
key2: {
itemId: "someId2",
myValue: "value2"
}
}
I also got an array to which I push items like this:
myArr.push({[item.itemId] : anotherDefinedObject}); //inside a loop on items
I then want to join all the items I pushed to the array to the first object. Meaning that if for example the items ids were "key3" and "key4" I would get this object:
{
key1: {
itemId: "someId",
myValue: "value"
},
key2: {
itemId: "someId2",
myValue: "value2"
},
key3: { //the object that was added },
key4: { //the object that was added }
}
I tried doing it with the spread operator:
return {...object, ...myArr}
But then instead of getting what I needed, I get "0", "1" and such as the keys in the new object (since 0,1 etc are the keys of the arrays).
How do I concatenate the object and the array the way I want?
rather my myArray create myObject.
myObject = {}
myObject[item.itemId] = anotherDefinedObject;
Then
return {...object, ...myObject}
const obj = {key1: 1};
const myArr = [{key2: 2}];
myArr.forEach(val => Object.assign(obj, val));
console.log(obj); // {key1: 1, key2: 2}
What you're looking to achieve here is not possible with the spread operator; it's working exactly as intended and the functionality cannot be changed as JS doesn't allow operator overloading. Your best bet is to loop through myArr and add each item in the array to the object using your own code.
P.S. As the comments suggest, in the future you should really provide more examples of your input, the current output, and your intended output; it was quite difficult to follow without it.
I'm currently working on a small application where I have to loop through an enormous array of objects. What would be the most efficient method to perform this?
var array = [
{
id: "1",
name: "Alpha"
},
{
id: "2",
name: "Beta"
},
...
];
I'd like to get each object where name equals "Alpha". I'm currently using a simple if statement to filter the objects with a different name value out, but I wonder if there's a more efficient way to do this, performance-wise.
It's worth to mention that I'll push the matching results into a new array.
No, there is no more efficient way.
The alternative is to build and maintain some kind of internal data structure which allows you to find the desired elements faster. As usual, the trade off is between the work involved in maintaining such a structure vs the time it saves you.
I don't have any way about which I would know it's more effective.
But if you had your objects ordered by name you could stop your search imideatly upon reaching an object whose name is not equal to "Alpha".
To find the first object you're looking for you can use binary search and from this Object you go up and down until at both ends you reach an object which isn't named "Alpha" or the end of array.
This is only a way of optimizing and will require time to sort the array and also will take more time when adding an element.
There's a JavaScript function exactly for this kind of task. Filter
From the Docs
The filter() method creates a new array with all elements that pass the test implemented by the provided function.
Here is a small example by code for getting all element from array which has a certain 'name' field:
const arr = [
{name: 'Abc'},
{name: 'Xyz'},
{name: 'Lmn'},
{name: 'Xyz'},
{name: 'Xyz'}
];
let response = findByName('Xyz');
console.log(response);
function findByName (name) {
return arr.filter((element) => {
return element.name = name;
});
}
If you need more than one time a collection with a given name, you could use an object with the names as hashes and have instantly access to the items.
var array = [{ id: "1", name: "Alpha" }, { id: "2", name: "Beta" }, { id: "3", name: "Beta" }, { id: "4", name: "Gamma" }, { id: "5", name: "Beta" }, { id: "2", name: "Alpha" }],
hash = Object.create(null);
array.forEach(function (a) {
if (!hash[a.name]) {
hash[a.name] = [];
}
hash[a.name].push(a);
});
console.log(hash);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I have a fairly complex array generated from Google's natural language API. I feed it a paragraph of text and out comes lots of language information regarding such paragraph.
My end goal is to find "key words" from this paragraph, so, to achieve this I want to put all the "entities" into a flat array, count the duplicates, and then consider words with the highest amount of duplicates to be "key words". If it doesn't find any then I'll cherry pick words from entities I consider most significant.
I already know the entities that could exist:
var entities = [
'art',
'events',
'goods',
'organizations',
'other',
'people',
'places',
'unknown'
];
Here is an example structure of the array I'm working with.
input = [
{
language: {
entities: {
people: [
{
name: "Paul",
type: "Person",
},
{
name: "Paul",
type: "Person",
},
],
goods: [
{
name: "car",
type: "Consumer_good",
}
], //etc
}
}
}
];
output = ["Paul", "Paul", "car"...];
My question is - what is the best way to convert my initial array into a flat array to then find the duplicates without using a whole bunch of FOR loops?
There is no way around loops or array functions if you work with dynamic input data.
You can access all the values using this format:
input[0]["language"]["entities"]["people"][0].name
input = [
{
language: {
entities: {
people: [
{
name: "Paul",
type: "Person",
},
{
name: "Paul",
type: "Person",
},
],
goods: [
{
name: "car",
type: "Consumer_good",
}
], //etc
}
}
}
];
console.log(input[0]["language"]["entities"]["people"][0].name);
Then you could do something like this:
for (var entry in input[0]["language"]["entities"]) {
console.log(entry);
}
OR, if I understood you wrong,
You can use this to turn the javascript Object into an array using this (requires jquery):
var myObj = {
1: [1, 2, 3],
2: [4, 5, 6]
};
var array = $.map(myObj, function(value, index) {
return [value];
});
console.log(array[0][0]);
console.log(array[0]);
console.log(array);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
This will output
1
[1, 2, 3]
[[1,2,3],[4,5,6]]
You could iterate through input.language.entities in a recursive way and collect all the .name properties into an array. Then you have only one for loop :-).
After doing that, you can iterate through it to find the duplicates. If you sort it alphabetical before it is easier (if two or more consecutive entries are equal, there are duplicates).
But it could be a bit dangerous if google changes the api or if it delivers crap data because of a malfunction.
Isn't input.language.entities already flat enough to work with it?
I ended up doing something like this. It's not pretty but it gets the job done.
var result = [];
var known_entities = ['art','events','goods','organizations','other','people','places','unknown'];
for(i=0; i < known_entities.length; i++){
var entity = known_entities[i];
if(language.entities[entity]){
for(var j in language.entities[entity]){
var word = language.entities[entity][j].name
result.key_words.push(word);
}
}
}
So I have two data sets. The mainData being the data I want to push to and display as the main data set.
// data set 1
var mainData = [{name: "david", views: 2}, {name: "andrew", views: 2}];
// data set 2
var newData = [{name: "andrew", views: 4}, {name: "david", views: 4}, {name: "chris", views: 2}];
The second data set is new or incoming data which I want to do one of two things with. I want to search through the main data set and see if any keys match, if so I just want to add views to the object with the same name. If the name key doesn't match any object in the mainData I want to then push that object to mainData.
My final mainData should look like this:
[{name: "david", views: 6}, {name: "andrew", views: 6}, {name: "chris", views: 2}]
Notice how david and andrew now have values of 6 while chris did not match any objects and was simply pushed. What is the most effiecient way of acheiving this in pure Javascript?
If you want to empty newData during processing do:
while (newData.length) {
var nd = newData.shift(), nam = nd.name, vie = nd.view;
if (!mainData.some(function(md) {
if (md.name === nam) {md.view += vie; return true;}
})) mainData.push(nd);
}
else if the objects in newData shall stay there do
newData.forEach(function(nd) {
var nam = nd.nam, vie = nd.view;
if (!mainData.some(function(md) {
if (md.name === nam) {md.view += vie; return true;}
})) mainData.push(nd);
});
In both cases mainData.some() iterates over mainData. Its callback function checks at each step whether the name-properties are identic. If so, the view-properties are added, the callback returns true (= "matching names found") and iteration is stopped. Otherwise the callback returns nothing and iteration goes on. Since some() is inside an negated condition, mainData.push() happens only if some() does not find a match.
Array.forEach() and some() are very fast. If they are not available, you have to use for-loops with less efficiency.