I am trying to write some code that will check to see if a group of numbers stored in an array exist in an object. With the code I have now it is always returning -1.
function checkHorizonal() {
var x= ['1', '2' ,'3'];
var y= ['4', '5', '6'];
var z= ['7', '8', '9']
console.log(jQuery.inArray(x, squaresClicked));
}
This is the squaresClicked object contents:
Object {1: "1", 2: "-1", 3: "1"}
You can see that the keys 1,2,3 exist but it will return -1.
From the jQuery doc:
jQuery.inArray( value, array [, fromIndex ] )
jQuery.inArray won't work the way you're using it. It checks for array contents, not object keys. Your value x is fine, but you're passing in an object instead of an array.
If you're trying to see if a set of integers exists as keys in an object, you can try the following (assuming you're using JavaScript >= 1.6):
myArray.filter(function(x) {
// check if value is a key
return (x in squaresClicked);
}).length == myArray.length;
Basically, we iterate through our array and return only those that exist as keys in the object squaresClicked. If the new array has the same length as our original list, then the values must all exist as properties in the object.
If you don't want to look up an objects entire prototype chain for the array value, you'll need to use hasOwnProperty instead of in.
Like so:
return (squaresClicked.hasOwnProperty(x));
You can read more about this method here.
jQuery's inArray can't deal with an array of needles, otherwise
$.inArray(x, Object.keys(squaresClicked));
would've worked. In this case you are stuck with iterating, I guess (though there might be some other tricky way – as always). One way in jQuery (though I don't very much like it for various reasons1):
var hasFailed = false;
$.each(x, function (index, value) {
if($.inArray(value, Object.keys(squaresClicked)) === -1) {
hasFailed = true;
}
});
return !hasFailed;
A basic vanillaJS approach:
for(var i = 0; i < x.length; i++) {
if(!squaresClicked.hasOwnProperty(x[i])) {
return false;
}
}
return true;
1 Two of the reasons why I dislike it:
It will iterate over the entire array, even if it's already clear that it will fail
It uses a double negation in its logic
Related
Task: convert an array into an object with one key-value pair, where the first array item is the key, and the last array item is the value.
E.g., [1,2,3] should convert to {1: 3}
I can't get it to work as:
function transformFirstAndLast(array) {
var firstLast = {
array[0]: array[-1]
};
return firstLast
}
But only as:
function transformFirstAndLast(array) {
var firstLast = {};
firstLast[array[0]] = array[array.length - 1];
return firstLast
}
...why doesn't the first work? Why can't you index the array for the key & value?
You could pop the last element and take a computed property for the object. (For the first element, you could take Array#shift, if you like to do it in the same manner.)
function transformFirstAndLast(array) {
return { [array[0]]: array.pop() };
}
console.log(transformFirstAndLast([1, 2, 3]));
ES5 with a temporary variable.
function transformFirstAndLast(array) {
var temp = {};
temp[array[0]] = array.pop();
return temp;
}
console.log(transformFirstAndLast([1, 2, 3]));
Take the first is easy, take the last is the size minus one like this:
function firstAndLast(array) {
var ary = {};
ary[array[0]] = array[array.length - 1];
return ary;
}
console.log(firstAndLast([1,2,3]))
First, you must remember than an array is a type of JavaScript object and, in JavaScript, an object property (a.k.a. "key") can be accessed or assigned in two ways:
via "dot notation"
object.property = value;
via array syntax
object["property"] = value;
Next, remember that, in JavaScript, if you assign a value to a property that doesn't exist (using either syntax from above), the property will be created, like in the following:
console.log(window.someNewProperty); // undefined
window.someNewProperty = 17; // This causes the property to be created
window["someOtherNewProperty"] = "Voilla!"; // So does this, just with array syntax
console.log(window.someNewProperty); // 17
console.log(window["someOtherNewProperty"]); // "Voilla!"
Now, moving on to the specifics of an array, it's critical to understand the difference between an object property/key name (which is always represented as a string) and an array index (which is always a non-negative integer up to the max integer in JavaScript). So, if you have an array and seemingly assign a value to a negative index, you are actually creating a property that is named the negative index and not actually adding to the length of the array or making a new indexed position in the array. We can see that here:
var myArray = ["a", "b", "c"];
myArray[-1] = 15;
console.log(myArray.length); // 3 not 4
console.log(myArray[-1]); // 15
// Now to prove that -1 is a string name for a new property and not an index:
console.log(myArray); // Notice no 15 in the indexed values?
// And, if we enumerate the object (not just the indexes), we'll see that we actually created
// a property with [-1], not a new index.
for(var prop in myArray){
// Note that prop is not the value of the property, it's the property name itself
console.log(typeof prop, prop, myArray[prop]);
}
So, to sum up, Arrays have non-negative integer indexes to store the items that make up the length of the array, but Arrays are also objects and have properties, like all other objects do. Any bracket assignments that use anything other than non-negative integers as the key name will become new properties, not array indices.
If this were .NET, I'd ask how to convert List<List<MyClass> to List<MyClass>. However, I'm not very good with javascript and don't know how to ask that as a question using Javascript terminology!
My javascript object comes through like
And is created as:
js_datasets.push({
"DataItem0": {
lzabel: "This",
data: [[1408710276000, null],[1408710276000, 15]]
},
"DataItem1": {
lzabel: "That",
data: [[1408710276000, null],[1408710276000, 15]]
},
});
js_datasets.push({
"DataItem22": {
lzabel: "And other",
data: [[1408710276000, null],[1408710276000, 5]]
},
"DataItem23": {
lzabel: "And lastly",
data: [[1408710276000, null],[1408710276000, 1]]
},
});
Each object is the same "type" (if it matters).
I'd like to create a single list but I am failing to do so. My efforts are
var myDataSet = []; //this is the results of what I want, ideally as a single list
for (var i = 0; i < js_datasets.length; i++) {
if (i==0) {
myDataSet.push(js_datasets[i]);
}
else {
myDataSet.concat(js_datasets[i]);//does nothing
myDataSet.join(js_datasets[i]);//does nothing
}
...more logic
As you can see with the above, I've tried using push, concat and join.
If I update the code to only use push (and never use concat and join) then I get all the values I want, but again, as an array within an array.
Using concat and join do not add to the list.
So, if we can assume the 12 items in the array (pictured) all contain 10 items, I'd like to have a single list of the 120 items!
How can I simply convert this multidimension array (is it multidimension) to a single dimension array.
This will be a bit complicated, as the items in your Array js_datasets are not Arrays, but a more generic Object. This means you can't assume the keys will be in order if you try to read them
Lets write some helper functions to account for this;
function dataItemCollectionToArray(o) {
var keys = Object.keys(o);
// assuming no non-DataItem keys, so next line commented out
// keys = keys.filter(function (e) {return e.indexOf("DataItem") === 0;});
keys.sort(function (a, b) { // ensure you will get the desired order
return +a.slice(8) - +b.slice(8);
});
return keys.map(function (e) {return o[e];});
}
Now you can loop over js_datasets performing this conversion
var myDataSet = [], i;
for (i = 0; i < js_datasets.length; ++i) {
// assuming no gaps, if you need to add gaps, also find min, max indices
// in `dataItemCollectionToArray`, and check them in each iteration here
myDataSet.push.apply(myDataSet, dataItemCollectionToArray(js_datasets[i]));
}
Please note that Object.keys and Array.prototype.map may require polifills if you wish to support old browsers, i.e. IE<=8
An easier solution however, may be to re-write how js_datasets is constructed so that the Objects you are pushing are more Array-like or indeed pushing true Arrays, perhaps with a couple extra properties so you know the offset for the first index. This would mean you can use flatten methods that you'll find around the internet
This is what I would like to become:
This is my javascript:
var retrievedObject = localStorage.getItem('exhibitor');
// CALL FUNCTION
parsePerObject(JSON.parse(retrievedObject));
function parsePerObject(data){
}
This is my object in my localStorage :
{"41873":{"id":"41873","external_id":"","eventid":"5588","venueid":"0","exhibitorcategoryid":"0","name":"Niels
Vroman","shortname":"","booth":"","imageurl":"","mapid":"0","y1":"0","x1":"0","x2":"0","y2":"0","description":"Niels
uit Zulte.","tel":"0497841121","address":"Drogenboomstraat
54","email":"vroman.niels#hotmail.com","web":"http://nielsvroman.be","code":"","username":"","password":"","image1":"","imagedescription1":"","image2":"","imagedescription2":"","image3":"","imagedescription3":"","image4":"","imagedescription4":"","image5":"","imagedescription5":"","image6":"","imagedescription6":"","image7":"","imagedescription7":"","image8":"","imagedescription8":"","image9":"","imagedescription9":"","image10":"","imagedescription10":"","image11":"","imagedescription11":"","image12":"","imagedescription12":"","image13":"","imagedescription13":"","image14":"","imagedescription14":"","image15":"","imagedescription15":"","image16":"","imagedescription16":"","image17":"","imagedescription17":"","image18":"","imagedescription18":"","image19":"","imagedescription19":"","image20":"","imagedescription20":"","order":"0","brands":[],"categories":[],"linktodetails":true,"imagethumb":""},"41877":{"id":"41877","external_id":"","eventid":"5588","venueid":"0","exhibitorcategoryid":"0","name":"Ferdau
Daems","shortname":"","booth":"","imageurl":"","mapid":"0","y1":"0","x1":"0","x2":"0","y2":"0","description":"Ferdau
Daems","tel":"0497683697","address":"Waregem","email":"fer.dau#gmail.com","web":"http://ferdau.be","code":"","username":"","password":"","image1":"","imagedescription1":"","image2":"","imagedescription2":"","image3":"","imagedescription3":"","image4":"","imagedescription4":"","image5":"","imagedescription5":"","image6":"","imagedescription6":"","image7":"","imagedescription7":"","image8":"","imagedescription8":"","image9":"","imagedescription9":"","image10":"","imagedescription10":"","image11":"","imagedescription11":"","image12":"","imagedescription12":"","image13":"","imagedescription13":"","image14":"","imagedescription14":"","image15":"","imagedescription15":"","image16":"","imagedescription16":"","image17":"","imagedescription17":"","image18":"","imagedescription18":"","image19":"","imagedescription19":"","image20":"","imagedescription20":"","order":"0","brands":[],"categories":[],"linktodetails":true}}
Does anyone know how I can sort alphabetically on the name and make a header from the first letter?
Say you have an Array of objects, not an Object of objects, to enable indexing and sorting. Objects don't have order.
You retrieve it from localStorage. You parse it.
var people = JSON.parse(localStoarge.getItem("exhibitor");
// now you have an array of objects, each object representing a person.
// regardless of what structure you have now, change it to achieve this.
var comparePersons = function(a, b) {
// this function will compare two people objects.
return a.name.localeCompare(b.name);
// it's using String.prototype.localeCompare which returns 1 if a.name > b.name,
// 0 for equal and -1 for smaller. localeCompare is lexicographic comparison.
};
people.sort(comparePersons);
// now you have the people sorted alphabetically.
You can run through the people array, get the unique start letters, make an array of out them, and then display data as you want. It should be fairly simple.
var letters = '', groups = {};
for (var i = 0, len = people.length; i < len; i++) {
var letterKey = people[i].name.charAt(0).toLowerCase();// get the first letter
if (letters.indexOf(letterKey)) == -1) {
letters += letterKey;
groups[letterKey] = [people[i]];// index the people by unique letters.
} else {
groups[letterKey].push([people[i]]);// add to the existing list. Another Syntax fix
};
};
At this point you have an object like this:
a: [person1, person2, person5, etc..]//the people at A.
b: [person 3, person 4, etc..]// the people at B.
Just use the above data to create the display. Anything more and I would have to invoice you:).
The tricks here are Array.prototype.sort(here is more on it) and String.prototype.localeCompare(read more here).
I have an array, and I want to remove just one element, but without reordering keys. Is there an easy way without using delete or rebuilding the entire array?
Or alternatively clean up after delete to get rid of the undefined values, fixing the length again.
var array = ["valueone", "valuetwo"];
console.dir(array); // keys 0 and 1
array.splice(0, 1);
console.dir(array); // key 1 is now 0, do not want!
You can delete the elements of an array:
a = ['one', 'two'];
delete a[0];
// a is now [undefined, 'two'];
alternatively, set a[0] explicitly to undefined.
Note that an arrays .length parameter is automatically maintained by the system. If you intentionally set it to a higher number, you'll just get a whole load of undefined values for the missing keys:
a.length = 10;
// a is now [undefined, 'two', undefined x 8]
If these semantics are not acceptable to you, then you should consider using an Object instead. This will preserve your keys, and perhaps be more efficient, but you lose the .length property.
couldn't you just explicitly set the value to undefined or null or an empty string. What are you trying to achieve?
var arr = ['aaaa','bbb','ccc','ddd'];
arr[0]= undefined;
//or
arr[0]= null;
///or
arr[0]= "";
arr.length; <--- 4
Update 2018-09-07
This answer isn't very good, in my opinion. I provided an answer on How do I remove a property from a JavaScript Object that has received much more attention from me over the years and covers this case and goes into much more detail.
The point is, you should be using Array.prototype.splice and Array.prototype.slice.
array.splice(start, n) returns a subset of array from index start with n sequential elements, and removes this subset from the original array, creating a new array in the process.
let array = [1,2,3,4,5,6];
array.splice(2,3); // [3,4,5]
array; // [1,2,6]
array.slice(start, end) returns a subset of array from index start to index end without mutating the original. The behavior is a little different from splice, which is why I prefer to call it as array.slice(start, start + n).
let array = [1,2,3,4,5,6];
array.slice(2, 2 + 3); // [3,4,5]
array; // [1,2,3,4,5,6]
Of course you could set the index to a sentinel value like null or "", but if you are wanting the array to stay in the same order after a deletion, perhaps you should change your approach--why does "valuetwo" have to be at index 1? What useful information is even being held in this data structure if the contents are always the same as the keys needed to access them?
The original answer is below. And if I am going to keep the original text, perhaps I should elaborate on why it's bad advice.
You can use javascript's delete keyword.
delete array[index];
Don't do this. If your array is homogeneous (as it ought to be), then this will corrupt your array by introducing a second type (undefined). You should use array.splice() as discussed above, which will create a new array with the specified range omitted.
Unfortunately, this creates an undefined index inside of the array
var arr = ['pie', 'cake', 'fish'];
delete arr[1];
arr; // ['pie', undefined, 'fish']
Case in point.
You could also do this:
var arr = [9,8,7,6];
arr[1] = null;
arr; // [9,null,7,6]
arr.length; // 4
var i = -1;
while(++i < arr.length){
if(arr[i] && typeof(arr[i] === "number")){
alert(arr[i]);
}
}
You could, but you shouldn't. Not only is this unnecessary, and doesn't do anything useful (because all it's doing is calling alert), but it's actually broken.
if(arr[i] && typeof(arr[i] === "number")){
alert(arr[i]);
}
You might expect this to only print our element if it is a non-zero number, but will in fact also run for values like "foo", [] and document.createElement("p"), because typeof(arr[i] === "number") will always return the value "boolean", which is a non-empty string, which is truthy and will therefore evaluate true. Which means the only requirement for alert to be called is that arr[i] is truthy. There are only six values in the entire language that will cause this if statement to not execute, and those are:
undefined
null
0
"" (pronounced "empty string")
false
NaN
Or, if you don't NEED to use arrays, you could use an object and make everything easier:
var obj = {
0: "first",
1: "second",
2: "third"
};
delete obj[1];
obj; // {0: "first", 2: "third"}
for(var i in obj){
alert(obj[i]);
}
Which would instantaneously erase all of the advantages to using an array. Now you have a data set which may or may not be heterogeneous, which can't be filtered, mapped, reduced or transformed in any sane way, and you have to resort to things like for(i in obj) (which is extremely bug-prone if you dare to use a library like jQuery) to iterate over it. Luckily today we have fancy stuff like Object.keys(obj).map(k => obj[k]).forEach(function(el){ ... }), but that's no excuse to have bad data structures.
To get the length of an object:
getLength = function(obj){
var i = 0, l = 0;
for(i in obj){
l++;
}
return l;
}
getLength(obj); // 3
Again, with arrays, this is unnecessary.
But remember that objects sort their indices by date of creation, not > by name. This shouldn't result in a road block, though.
To sort the indices of an object alphabetically:
sortObject = function (){
var arr = [], i;
for(i in this){
arr.push({index:i,content:this[i]});
delete this[i];
}
arr.sort();
for(i in arr){
var item = arr[i];
this[item.index] = item.content;
}
return this; // make chainable
}
var obj = {
acronym: "OOP",
definition: "Object-Oriented Programming",
article: "http://wikipedia.org/OOP"
};
sortObject.apply(obj); // indices are "acronym", "article", "definition"
array.sort(fn)
The whole point of an object is that its properties are unsorted, anyway. Sorting an unsorted list will hardly do anything useful.
Just to illustrate how much better arrays are at doing array things:
let array = ["pie", "cake", "fish", "brownie", "beef", ...];
/* do some stuff... */
array
.filter(el => exclude.indexOf(el) === -1)
.forEach(function(el){
console.log(el);
});
if exclude is ["cake", "brownie"], then this will log the following to the console:
pie
fish
beef
...
Just try to imagine how many unnecessary lines of code it would take to do the same using the approach from the previous version of this answer.
Hope this helped
Hopefully this update helped.
I have an array of objects which I need placed in a certain order, depending on some configuration data. I am having a problem with itterating through the array in the proper order. I thought that if I made the array, and then stepped through with a for loop, I would be able to execute the code correctly. It is working great except in one use case, in which I add the fourth item to the array and then go back to the third.
links[0] = foo
links[1] = bar
links[2] = foobar
links[3] = a_herring
links[4] = a_shrubery
order = [] //loaded from JSON, works has the numbers 1 2 3 or 4 as values
//in this case:
order[0] = 1
order[1] = 2
order[2] = 4
order[3] = false
order[4] = 3
for(x in order){
if(order[x]){
printOrder[order[x]]=links[x]
//remember that in this case order[0] would
}
This should give me an array that looks like this:
//var printOrder[undefined,foo,bar,a_shrubbery,foobar]
But when I try to itterate through the array:
for(x in printOrder){
printOrder[x].link.appendChild(printOrder[x].image)
printOrder[x].appendChild(printOrder[x].link)
printOrder[x].appendChild(printOrder[x].text)
document.getElementById("myDiv").appendChild(printOrder[x]);
}
I get foo, bar, foobar, a_shrubbery as the output instead.
I need to either sort this array by key value, or step through it in the correct order.
Iterating over the numerically-index properties of Array instances should always be done with a numeric index:
for (var x = 0; x < printOrder.length; ++x) {
// whatever with printOrder[x]
}
Using the "for ... in" form of the statement won't get you predictable ordering, as you've seen, and it can have other weird effects too (particularly when you mix in JavaScript frameworks or tool libraries or whatever). It's used for iterating through the property names of an object, and it doesn't treat Array instances specially.
You need to create a function for finding values in an array like this:
Array.prototype.indexOf = function(value)
{
var i = this.length;
while ( i-- )
{
if ( this[ i ] == value ) return i;
}
return -1;
};
You can then use it like this:
//NOTICE: We're looping through LINKS not ORDER
for ( var i = 0; i < links.length; i++ )
{
var index = order.indexOf( i );
//It's in the order array
if ( index != -1 ) printOrder[ i ] = links[ i ];
}
REMEMBER: You need to make sure the values returned in json are integers. If they're strings, then you'll need to convert the integers to string when passed to indexOf.
The function you have in your question works as you suggest it should.
http://jsfiddle.net/NRP2D/8/ .
Clearly in this simplified case you have removed whatever error you are making in the real case.