Example:
var myArray = ['e', {pluribus: 'unum'}];
How do I get the first 'e'?
My actual array looks like this:
({'U.S., MCC':{score:"88.88", url:"http://ati.publishwhatyoufund.org/donor/usmcc/"}, GAVI:{score:"87.26", url:"http://ati.publishwhatyoufund.org/donor/gavi/"}, 'UK, DFID':{score:"83.49", url:"http://ati.publishwhatyoufund.org/donor/ukdfid/"}, UNDP:{score:"83.38", url:"http://ati.publishwhatyoufund.org/donor/undp/"}, 'World Bank, IDA':{score:"73.81", url:"http://ati.publishwhatyoufund.org/donor/world-bank-ida/"}, 'Global Fund':{score:"70.65", url:"http://ati.publishwhatyoufund.org/donor/global-fund/"}})
I need to get the name. i.e 'U.S., MCC' and then the score and the url - I am using this in highcharts as data points in a graph.
I know it should be simple, but I am a complete JS noob.
Thanks
To get the first element from your array, just use this:
myArray[0]
Notice that 0 points at the first element in the array. Arrays are zero-indexed.
Have a look at this mdn page about arrays to learn more.
However, what you have there isn't an array, it's an object. You can't access those with numeric keys (like 0, 1, 2 etc)
To get the first element of your object, you have to use the "key" to access that value.
Assuming:
var myObject = {'U.S., MCC':{score:"88.88", url:"http://ati.publishwhatyoufund.org/donor/usmcc/"}, GAVI:{score:"87.26", url:"http://ati.publishwhatyoufund.org/donor/gavi/"}, 'UK, DFID':{score:"83.49", url:"http://ati.publishwhatyoufund.org/donor/ukdfid/"}, UNDP:{score:"83.38", url:"http://ati.publishwhatyoufund.org/donor/undp/"}, 'World Bank, IDA':{score:"73.81", url:"http://ati.publishwhatyoufund.org/donor/world-bank-ida/"}, 'Global Fund':{score:"70.65", url:"http://ati.publishwhatyoufund.org/donor/global-fund/"}}
Then:
myObject['U.S., MCC']
Will be:
{score:"88.88", url:"http://ati.publishwhatyoufund.org/donor/usmcc/"}
Or, as a more simple example:
var foo = {
'bar': 1,
'wut': {'nested': 'you can nest objects! (and arrays, etc)'}
baz: 'Objects, woo!', // Quotes around keys aren't mandatory, unless you have
} // spaces in the keys: 'quotes mandatory'
foo['bar'] // 1
foo.wut.nested // 'you can nest objects! (and arrays, etc)'
foo.baz // 'Objects, woo!' (you don't have to use the square brackets,
// if the key is a simple string (No spaces))
Have a look at this mdn article about working with objects to learn more about those.
Now, to actually get the "first" element in that object is tricky, since objects aren't sorted. (Even though they may appear so.)
You can loop through an object using a for...in, but there's no guarantee the items will show up in the same order, on different browsers:
for (var key in myObject) {
if (myObject.hasOwnProperty(key)) { // Make sure it's a proper element on the object, not a prototype function.
// key == ''U.S., MCC', for example,
doSomethingWith(myObject[key]);
}
}
You can iterate over objects in a sorted order, but there's some better answers out there about that.
Try to use this case:
var myObj = {'U.S., MCC':{score:"88.88", url:"http://ati.publishwhatyoufund.org/donor/usmcc/"}, GAVI:{score:"87.26", url:"http://ati.publishwhatyoufund.org/donor/gavi/"}, 'UK, DFID':{score:"83.49", url:"http://ati.publishwhatyoufund.org/donor/ukdfid/"}, UNDP:{score:"83.38", url:"http://ati.publishwhatyoufund.org/donor/undp/"}, 'World Bank, IDA':{score:"73.81", url:"http://ati.publishwhatyoufund.org/donor/world-bank-ida/"}, 'Global Fund':{score:"70.65", url:"http://ati.publishwhatyoufund.org/donor/global-fund/"}};
for(v in myObj) {
console.log("Obj key: "+v, myObj[v]);
}
Related
I am trying to maintain the order of an array with mixed key types. The array contains mostly keys represented by string values -- but if you enter a numbered key it goes to the front. How can I force a key which is a number to be a string type?
E.g.
array = [];
array["one"] = "some data";
array["two"] = "some more data";
array["3"] = "this should not be the first element";
How can I make "3" a string type to prevent it from moving to the top of the index?
Oh wow did you ever open multiple cans of worms.
Javascript arrays are a special type of Javascript objects, and like all Javascript objects they can have arbitrary string properties:
const foo = [];
foo["bar"] = "hi";
However that string is a property of the array object, not an item in the array:
foo.forEach(console.log); // logs nothing
You can still access it like any other object property:
console.log(foo["bar"]); // "hi"
But it won't show up in the usual iterative constructs like c-style for loops or the map/forEach array methods.
The line in your example
array["3"] = "this should not be the first element";
is very different however, because of Javascript's playing fast and loose with type conversions this actually sets the string to the 4th slot in the array:
const bar = [];
bar["3"] = "oops!"; // equivalent to bar[3] = "oops!"
console.log(bar); // [empty x 3, "oops!"]
This piece of it is actually a good thing (other than the implicit conversion part) rather than a problem: sometimes you need a sparse array and JS supports those. Iterating it will only produce the one element:
bar.forEach((item, index) => console.log(item, index)); // ["oops", 3]
Note though that the string has the correct index of 3, and can be accessed that way even though there's nothing "in front" of it:
bar[3]; // "oops"
So the first two assignments in your example create properties on the array object, and the third assignment is the only one that actually adds an item to the array, at the 4th index (there's nothing at the first 3).
What you seem to want as Reese Casey suggests, is a plain object:
const foo = {}; // curly
foo["some string"] = "whatever";
However now the properties are basically unordered. If you want them to be in a guaranteed specific order you do want an array, but all your indicies will need to be integers, and should be sequential. You can achieve this easily by using the .push method:
foo = [];
foo.push("something");
foo.push("something else");
Now foo will have two elements, in the correct order, and index 0 and 1 respectively.
Update based on comment on the other answer:
I want some of the data to be ordered, and the rest of the data to follow
This can be accomplished through object destructuring:
const responseFromDB = {
oneKeyICareAbout: 3,
anotherKeyICareAbout: 2,
foo: 6,
bar: 7,
};
const {
oneKeyICareAbout,
anotherKeyICareAbout,
*rest,
} = responseFromDB;
const stuffToDisplay = [
oneKeyICareAbout,
anotherKeyICareAbout,
...Object.values(rest),
]; // [3, 2, 6, 7]
And at least the destructured stuff you put in the array will be ordered because by doing so you've ordered it.
Javascript arrays cannot have string indexes. This is actually working incorrectly as the index is adding a property to the array object.
Changing to an object makes more sense for this.
EDIT: Whilst below its mentioned you can have string indexes you are not actually using the array by doing so. The answer by Jared Smith goes into much more detail as to why.
The other answers explain what is happening with your array-object mixture. For having an indexable thing which can reproduce the original order, you can use a Map:
The Map object holds key-value pairs and remembers the original insertion order of the keys.
array = new Map();
array.set("one","some data");
array.set("two","some more data");
array.set("3","this should not be the first element");
console.log("Test of get:",array.get("two"));
console.log("Test of order:");
for(let entry of array)
console.log(entry);
So I have an interesting issue I am not sure how to follow, I need to use lodash to search two arrays in an object, looking to see if x already exists, lets look at a console out put:
There are two keys I am interested in: questChains and singleQuests, I want to write two seperate functions using lodash to say: find me id x in the array of objects where questChains questChainID is equal to x.
The second function would say: Find me a quest in the array of objects where singleQuests questTitle equals y
So if we give an example, you can see that questChainId is a 1 so if I pass in a 1 to said function I would get true back, I don't actually care about the object its self, else I would get false.
The same goes for singleQuests, If I pass in hello (case insensitive) I would get back true because there is a quest with the questTitle of 'Hello'. Again I don't care about the object coming back.
The way I would write this is something like:
_.find(theArray, function(questObject){
_.find(questObject.questChains, function(questChain){
if (questChain.questChainId === 1) {
return true;
}
});
});
This is just for the quest chain id comparison. This seems super messy, why? Because I am nesting lodash find, I am also nesting if. It gets a bit difficult to read.
Is this the only way to do this? or is there a better way?
Yeah it can be expressed more simply.
Try something like this:
var exampleArray = [{
questChains: [{
questChainId: 1,
name: 'foo'
}, {
questChainId: 2,
name: 'bar'
}],
singleQuests: [{
questTitle: 'hello world'
}]
}, {
questChains: [{
questChainId: 77,
name: 'kappa'
}]
}];
var result = _.chain(exampleArray)
.pluck('questChains')
.flatten()
.findWhere({ questChainId: 2 })
.value();
console.log('result', result);
<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/3.5.0/lodash.min.js"></script>
Using chain and value is optional. They just let you chain together multiple lodash methods more succinctly.
pluck grabs a property from each object in an array and returns a new array of those properties.
flatten takes a nested array structure and flattens it into flat array structure.
findWhere will return the first element which matches the property name/value provided.
Combining all of these results in us fetching all questChain arrays from exampleArray, flattening them into a single array which can be more easily iterated upon, and then performing a search for the desired value.
Case-insensitive matching will be slightly more challenging. You'd either need to either replace findWhere with a method which accepts a matching function (i.e. find) or sanitize your input ahead of time. Either way you're going to need to call toLower, toUpper, or some variant on your names to standardize your search.
Javascript newbie here --
I have the following array:
var group = ({
one: value1,
two: value2,
three: value3
});
I want to check if array "group" is part of "groupsArray" and add it if doesn't or remove it if it does.
var groupLocate = $.inArray(group, groupsArray);
if(groupLocate ==-1){
groupsArray.push(group);
} else {
groupsArray.splice($.inArray(group, groupsArray),1);
}
This method works with single value arrays. Unfortunately, I can't get it to work in this case with three keys and values as groupLocate always returns -1.
What am I doing wrong?
Thanks.
First it helps to understand why $.inArray() didn't work. Let's try a simpler case. Paste this in to the JavaScript console in your browser on a page with jQuery loaded (such as this page we're on) and run it:
var object = { a: 1 };
var array = [ { a: 1 } ];
console.log( '$.inArray: ', $.inArray( object, array ) );
(Note the terminology: your group variable is an Object, not an Array.)
Now it looks like object is in the array, right? Why does it print -1 then? Try this:
console.log( object );
console.log( array[0] );
They look the same. How about:
console.log( '== or === works? ', object == array[0], object === array[0] );
Or even simpler:
console.log( 'Does {a:1} == {a:1}? ', {a:1} == {a:1} );
console.log( 'What about {} == {}? ', {} == {} );
Those all print false!
This is because two objects that happen to have the same content are still two separate objects, and when you use == or === to compare two objects, you are actually testing whether they are both references to one and the same object. Two different objects will never compare equal, even if they contain exactly the same content.
$.inArray() works like using an === operator to compare two objects - it won't find an object in an array unless it is the same object, not just an object with identical content.
Knowing this, does that suggest any possible ways to approach the problem? There are several ways you could write your own code to search the array for your object, or you may find it helpful to use a library such as Underscore.js which has many useful methods for arrays and objects.
For example, you could use _.findWhere( groupsArray, group ) to find the first match - with the caveat that it only compares the properties that are in the group object. For example, if group is {a:1}, it would match an object in the groupsArray array that was {a:1,b:2}.
If you need an exact match, you could combine Underscore's _.find() and _.isEqual() methods:
var index = _.find( groupsArray, function( element ) {
return _.isEqual( element, group );
});
Now one last thing to watch out for. Your code that pushes the group object onto the groupsArray array - you know that pushes the actual group object itself. It doesn't make a copy of it in the array, it's a reference to the very same object. (Ironically, this means that your original code to find group in the array would actually work in the case where you'd pushed that same group object onto the array yourself.)
If you want to make sure the elements in groupsArray are each their own independent object, and not a reference to another object floating around in your code, you can use another Underscore method to do a shallow copy:
groupsArray.push( _.clone(group) );
If group has any nested objects, though, this won't copy them. (I don't see a deep copy function in Underscore, although you could write one if you need it.)
I am dynamically building an array of objects using a process that boils down to something like this:
//Objects Array
var objects = [];
//Object Structure
var object1 = {"id":"foobar_1", "metrics":90};
var object2 = {"id":"some other foobar", "metrics":50};
objects[0] = object1;
objects[1] = object2;
(Let it be said for the record, that if you can think of a better way to dynamically nest data such that I can access it with objects[i].id I am also all ears!)
There's ultimately going to be more logic at play than what's above, but it's just not written yet. Suffice it to say that the "object1" and "object2" parts will actually be in an iterator.
Inside that iterator, I want to check for the presence of an ID before adding another object to the array. If, for example, I already have an object with the ID "foobar_1", instead of pushing a new member to the array, I simply want to increment its "metrics" value.
If I wasn't dealing with an array of objects, I could use inArray to look for "foobar_1" (a jQuery utility). But that won't look into the object's values. The way I see it, I have two options:
Keep a separate simple array of just the IDs. So instead of only relying on the objects array, I simply check inArray (or plain JS equivalent) for a simple "objectIDs" array that is used only for this purpose.
Iterate through my existing data object and compare my "foobar_1" needle to each objects[i].id haystack
I feel that #1 is certainly more efficient, but I can't help wondering if I'm missing a function that would do the job for me. A #3, 4, or 5 option that I've missed! CPU consumption is somewhat important, but I'm also interested in functions that make the code less verbose whether they're more cycle-efficient or not.
I'd suggest switching to an object instead of an array:
var objects = {};
objects["foobar_1"] = {metrics: 90};
objects["some other foobar"] = {metrics: 50};
Then, to add a new object uniquely, you would do this:
function addObject(id, metricsNum) {
if (!(id in objects)) {
objects[id] = {metrics: metricsNum};
}
}
To iterate all the objects, you would do this:
for (var id in objects) {
// process objects[id]
}
This gives you very efficient lookup for whether a given id is already in your list or not. The only thing it doesn't give you that the array gave you before is a specific order of objects because the keys of an object don't have any specific order.
Hmm , i wonder why dont you use dictionary cause that is perfectlly fits your case. so your code will be as below:
//Objects Array
var objects = [];
//Object Structure
var object1 = {"metrics":90};
var object2 = {"metrics":50};
objects["foobar_1"] = object1;
objects["some other foobar"] = object2;
// An example to showing the object existence.
if (!objects["new id"]){
objects["new id"] = {"metrics": 100};
}
else {
objects["new id"].matrics++;
}
What does the following syntax mean:
1 in [1,2,3,5]
I know it doesn't search for 1 in the array. But what does it do?
I've seen it used in loops:
for (var i in testArray)
{
}
But have also seen this used by itself. Does it mean check if the literal is a valid index in the array or object that is the other operand?
Very simply, it's an object property search:
print ('a' in {'a':1, 'b': 2}); // true
print ('c' in {'a':1, 'b': 2}); // false
Live demo.
This is subtly different to the similar use of in in for loops.
Also note that it should not be used with arrays, although this is a common error to make.
It is unspecified what properties besides numeric keys make up the internals of an array, so you should stick to the Array API (e.g. indexOf) if you're using Arrays, otherwise you'll end up with behaviour that you may not expect:
print ('length' in [1,2,3,4]); // true
literalinobject means: "Get a property literal from object."
When used in a loop, the engine will try to access all properties of the object.
1 in [1,2,3,4] doesn't check for an occurence of an element with a value of 1, but it checks whether element 1 (array[1]) exists or not.
It looks like a cheap way not to use a traditional for loop for each item in the array.
Your 2nd example is a for-each loop. It doesn't have the literal 1 (one).
It's used to iterate JavaScript objects.
This loop will iterate through each "key" in the object.
Its common usage is iterate through such objects:
var Car = { color: "blue", price: 20000 };
for (var key in Car)
console.log("Propery " + key + " of Car is: " + Car[key]);
Live test case - check Chrome/Firefox JavaScript console to see the output.
When used for plain arrays, each "key" will be the index.. for example:
var nums = [20, 15, 30]
for (var key in nums)
console.log("Propery " + key + " of array is: " + nums[key]);
Will show the keys as 0, 1 and 2. Updated fiddle for such case.
'in' operator returns true if specified property exists in specified object; used in a loop it allows you to iterate over all properties of the object