Array Object Acceptable Globally, but Not in Loops - javascript

So I have an array, which is populated with objects. The objects have two values, one containing a list item, and another containing a float (price). I'm trying to push the list into a DOM element, but the variable is globally undefined.
This code outputs the second array item to the console:
$('#coll-price-filter').change(function() {
var newList = [];
$('#coll-product-list li').each(function(idx, li) {
pprice = $(li).find('.coll-prod-price').html().trim().substring(1)
pprice = parseInt(pprice);
newList[idx] = {
value: $(li).wrap('<div></div>').parent().html(),
price: pprice
}
newList.sort(function(a, b){
a = a.price, b = b.price;
return a > b ? 1 : a < b ? -1 : 0;
});
});
console.log(newList[1].value);
});
However this does not
$('#coll-price-filter').change(function() {
var newList = [];
$('#coll-product-list li').each(function(idx, li) {
pprice = $(li).find('.coll-prod-price').html().trim().substring(1)
pprice = parseInt(pprice);
newList[idx] = {
value: $(li).wrap('<div></div>').parent().html(),
price: pprice
}
newList.sort(function(a, b){
a = a.price, b = b.price;
return a > b ? 1 : a < b ? -1 : 0;
});
});
i = newList.length;
while (i > 0) {
console.log(newList[i].listItem);
i--;
}
});
So it appears that the while loop is breaking the accessibility of the newList[] object. I've tried it a few ways, and it works if I'm inside the .each() iterator. But I need to access it outside.

Because Array indices are 0 based, this:
i = newList.length;
should be this:
i = newList.length - 1;
Otherwise the starting index is out of bounds, so newList[i] will be undefined, and accessing a property on undefined is a TypeError.
Once you correct that, you probably want to access a property defined on the object, like .value or .price, otherwise it will log undefined for each iteration.

Shouldn't this:
i = newList.length;
while (i > 0) {
console.log(newList[i].listItem);
i--;
}
Be this?
i = newList.length-1; // start on the last index, not length
while (i > 0) {
console.log(newList[i].value); // value, like in your top example
i--;
}

Related

Javascript Searching Array for partial string

Have a function that returns an array of objects. The array has a rate object that has a name field. Inside the name field are names such as "Slow speed" and "Fast speed".
I have written the following in hopes to create a new array that will filter out the array values and just return only those with "Slow" that matches from the rates[i].name.
So far I am encountering this error in my dev console.
"Uncaught TypeError: value.substring is not a function"
var rates = myArray();
var index, value, result;
var newArr = [];
for (index = 0; index < rates.length; ++index) {
//value = rates[index];
if (value.substring(0, 5) === "Stand") {
result = value;
newArr.push();
break;
}
}
Part of array return in console.
"rates":[{"id":1123,"price":"1.99","name":"Slow speed - Red Car","policy":{"durqty":1,"durtype":"D","spdup":15000,"spddwn":15000}
You have an object at each array location not the string itself, try this instead:
var rates = myArray();
var index, value, result;
var newArr = [];
for (index = 0; index < rates.length; ++index) {
name = rates[index].name;
if (name.substring(0, 4) === "Slow") {
newArr.push(rates[index]);
}
}
Try using filter function like this, it is much more cleaner to see
var newArr = rates.filter(function(rate){
return rate.name && rate.name.substring(0,4) === "Slow";
});
You can use filter to do this, for example:
var newArr = rates.filter(function(val){
// check if this object has a property `name` and this property's value starts with `Slow`.
return val.name && val.name.indexOf("Slow") == 0;
});
As #4castle mentioned, instead of indexOf(...) you can use slice(...) which may be more efficent, eg: val.name.slice(0,4) == "Slow"

cut object's value to the last JavaScript

How can I cut the 6th object's value and paste it into the last object? Below is the result of this code :
JSON.parse(json).forEach(function(obj, idx, array) {
console.log(obj);
});
Updated: As you mentioned that if any object has an value must be cut
and moved to the last,
var array = JSON.parse(json),
index;
array.forEach(function(obj, idx) {
if(obj.itemId) {
index = idx;
}
});
if(typeof index !=="undefined") {
var tempObj = array.splice(index,1);
// adding it the end
array.push(tempObj);
}
It will remove the last element with itemId and move it to the end.
If I understand your question, you want to replace the last object with the object with type:"award".
Then I would do it like this:
JSON.parse(json).forEach(function(obj, idx, array) {
if (obj.type === "award") {
array[array.length - 1] = obj;
}
});
if the award is already the last, it will only be overwritten by itself.
Considering that your get an array of objects, iterate through all the objects and you will end up with the last object that has award in its type key.
for(var i = 0, _len = obj.length; i < _len; i += 1) {
if(obj[i].type === "award") {
ourObj = obj[i];
}
}
obj[obj.length-1] = ourObj;
James,
I have some few question just to get my understanding clear before providing an answer.
So, you want to remove the 6th item in array and want to replace that with the last item ?
The item you are going to remove is always going to be 6th item ?
Answer:
var item, items = JSON.parse(json), itemCount = items.length, obj, position;
for (var i = 0; i < itemCount; i++) {
item = items[i];
if (item.itemId) {
position = i;
}
}
if (position) {
items.push(items.splice(position, 1));
}
The code above will make sure that if the item appears at last position will also be handled. If you want to clone the object instead of referencing the old one then you need to loop through the object and update the new one like below
if (position) {
obj = items.splice(position, 1);
item = {};
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
item[property] = obj[property];
}
}
items.push(item);
}
Just filter it:
var res = JSON.parse(json).filter(function(value) {
return value.itemId == 6;
});
Use Array.prototype.splice() to remove the element you want. Push it to the end.
var arr = [];
var tgtIdx = -1;
var lastID = -1;
JSON.parse(json).forEach(function (obj, idx, array) {
if(obj.itemId !== null && obj.itemId > lastID) {
tgtIdx = idx;
lastID = obj.itemId;
}
arr.push(obj);
})
if(tgtIdx >= 0 && tgtIdx < arr.length - 1) {
arr.push(arr.splice(tgtIdx, 1)[0]);
}

Are there such things as dynamic-dimensional arrays in JavaScript?

What I mean by dynamic-dimensional arrays is multidimensional arrays that can have various dimensions. I need to create a function that does something to elements of multidimensional arrays, regardless of their dimensions. I wrote a function that should loop through all elements of a multidimensional array, but I can't find a way to get them. Here's what I wrote:
function loopThrough (multiArray, dimensions) {
var i, indexes = new Array(dimensions.length);
// stores the current position in multiArray as index combination
for (i in indexes) indexes[i] = 0; // position is initialised with [0, 0, ... 0]
while (i >= 0) {
doStuff(multiArray[indexes[0], indexes[1], ... indexes[?]]); // this is where I got stuck
for (i = indexes.length - 1; i >= 0 && ++indexes[i] >= dimensions[i]; indexes[i--] = 0);
// creates the next index combination
}
}
I also need a way to create such arrays. Say in an object's constructor, like:
function MultiArray (dimensions) {
this.array = [];
// create multidimensional array
}
For example, if I want to create a 5x3x8 array I should be able to call MultiArray([5,3,8]); just the same as calling MultiArray([4,6]); for a 4x6 array, or MultiArray([7]); for a plain 7-lengthed array.
You can use something like this:
function MultiArray(dimensions) {
var a = [];
if (dimensions > 1) {
a.push(MultiArray(dimensions -1));
}
return a;
}
var m = MultiArray(4);
function MultiArray(dimensions) {
this.elements = [];
var leaf = dimensions.length == 1;
var dimension = dimensions.shift();
for (var i = 0; i < dimension; ++i) {
this.elements.push(leaf ? undefined : new MultiArray(dimensions));
}
}
MultiArray.prototype.get(indexes) {
var leaf = indexes.length == 1;
var index = indexes.shift();
return leaf ? this.elements[index] : this.elements[index].get(indexes);
}
MultiArray.prototype.set(indexes, value) {
var leaf = indexes.length == 1;
var index = indexes.shift();
if (leaf) {
this.elements[index] = value;
} else {
this.elements[index].set(indexes, value);
}
return this;
}
var m = new MultiArray([4, 3, 5]);
m.set([1, 2, 4], "i'm a value in a multi dimensional array");
m.get([1, 2, 4]); // should return "i'm a value in a multi dimensional array"
m.get([2, 0, 3]); // should return undefined
m.get([0, 1]); // should return an array of 5 elements

javascript sort obj changing id #'s

i'm trying to sort my hash table pull down menu alphabetically... using this function:
function getSortedKeys(obj) {
var keys = [];
for(var key in obj) {
keys.push(obj[key]);
keys[keys.length-1]['key'] = key;
}
return keys.sort(function(a,b){
return a.name > b.name ? 1 : a.name < b.name ? -1 : 0;
});
}
This sorts the pull down menu...although it changes the original id# of my menu items which screws some things up on my site... is it possible to keep the original id# of each menu item and still sort?
sorry..here's the hash code:
var clientProjectsHash = {};
clientProjectsHash['1'] = {};
clientProjectsHash['1']['name'] = 'RONA';
clientProjectsHash['2'] = {};
clientProjectsHash['2']['name'] = 'CMS';
clientProjectsHash['3'] = {};
clientProjectsHash['3']['name'] = 'ALT';
and getSortedKeys is called by:
function getInitialClient() {
clientProjectsHash = getSortedKeys(clientProjectsHash);
for (clientKey in clientProjectsHash) {
if(clientKey > 0) {
return clientKey;
}
}
}
The problem is you are returning an array, and expecting it to be an object. These are different things in JavaScript. Nothing is "changing"; your "ids" (or "hashes") are not being modified.
Your clientProjectsHash starts as an object! Objects are unordered and can have any string as a key. When you do getSortedKeys(clientProjectsHash); you are being returned an array! Arrays are ordered, and have numeric indexes (keys) that start at 0.
clientProjectsHash = getSortedKeys(clientProjectsHash);
for (clientKey in clientProjectsHash) {
}
This overwrites clientProjectsHash with an array. Then you for..in over it (you should not use for..in for arrays, by the way).
The array returned from getSortedKeys looks like this:
[
{
name: 'ALT',
key: 3
},
{
name: 'CMS',
key: 2
},
{
name: 'RONA',
key: 1
}
]
So, in your for..in, clientKey will be 0, 1, and 2. The indexes of the array. Your key values are not changing, you are just reading the wrong value.
Try this instead:
function getInitialClient() {
var clientKeys = getSortedKeys(clientProjectsHash);
for(var i = 0, len = clientKeys.length; i < len; i++){
var clientKey = clientKeys[i];
if(clientKey.key > 0){
return clientKey.key;
}
}
}

Push objects to array so long as object property is not NaN

I am aware that I could use .filter to achieve this, however I am not sure how to implement it.
I have objects as follows within an array
item {
title : g.attributes.title,
category : g.attributes.categoryid,
possible: g.attributes.possible
}
however, some items in the array have a possible property of NaN.
I need to make sure that only items whose possible property is not NaN, are pushed into the array.
Here is an excerpt of my complete code:
function load(id){
itemPath = lev1.lev2.lev3;
items = [];
for (var i = 0; i<itemPath.length; i++) {
if(itemPath[i].attributes.id==id) {
return itemPath[i].attributes.grades.models.map(function(g) {
items.push(
{
title : g.attributes.title,
category : g.attributes.categoryid,
possible: g.attributes.possible
});
});
}
}
}
function load(id){
itemPath = lev1.lev2.lev3;
items = [];
for (var i = 0; i<itemPath.length; i++) {
if(itemPath[i].attributes.id==id) {
return itemPath[i].attributes.grades.models.map(function(g) {
if(g.attributes.possible !== g.attributes.possible){
return;
}
items.push(
{
title : g.attributes.title,
category : g.attributes.categoryid,
possible: g.attributes.possible
});
});
}
}
}
NaN is the only property in javascript that does not equal itself. Just loop over the properties and check them for this, or use the built in NaN() function within the loop as suggested elsewhere.
Update
Since you're only worried about the possible property, just check that one as part of the if statement using === self, or isNaN()
Just change your test line from
if(itemPath[i].attributes.id==id)
to use isNaN function on the properties you want to check
var attr = itemPath[i].attributes;
if (attr.id==id && !isNaN(attr.title) && !isNaN(attr.categoryid) && !isNaN(attr.possible))
You can use the isNaN() and test it before adding it...
function load(id){
itemPath = lev1.lev2.lev3;
items = [];
for (var i = 0; i<itemPath.length; i++) {
if(itemPath[i].attributes.id==id) {
return itemPath[i].attributes.grades.models.map(function(g) {
if( isNaN(g.attributes.title) || isNaN(g.attributes.categoryid) || isNaN(g.attributes.possible) ){
items.push(
{
title : g.attributes.title,
category : g.attributes.categoryid,
possible: g.attributes.possible
});
}
});
}
}
}
You're code is a little confusing
function load(id){
itemPath = lev1.lev2.lev3;
items = [];
for (var i = 0; i<itemPath.length; i++) {
if(itemPath[i].attributes.id==id) {
return itemPath[i].attributes.grades.models.map(function(g) {
items.push(
{
title : g.attributes.title,
category : g.attributes.categoryid,
possible: g.attributes.possible
});
});
}
}
}
It doesn't look like you are using map right. Map works like list compresions in the sense that it iterates over a sequence to preform some kind of operation on each element and returns a new sequence
var arr = [1,2,3];
var complexMagic = arr.map( function(n) { return n + 10; } );
// complexMagic === [11,12,13]
FYI, this is how filter, works. Filter takes in a predicate function( aka, Boolean function) to build a new sequence. If the predicate returns true, then the element will be stored in the new sequence.
var arr = [1, 123, 42, 1001, 1100];
var oddNumbers = arr.filter( function(n) {
return 1 === (n & (-n) );
} );
// oddNumbers === [1, 123, 1001] );
// Bit hacks are fun ;P
It looks like you don't need items array or to even push new elements onto it.
function load(id){
itemPath = lev1.lev2.lev3;
items = [];
for (var i = 0; i<itemPath.length; i++) {
if(itemPath[i].attributes.id==id) {
return itemPath[i].attributes.grades.models.map(function(g) {
// You don't have to return anything.
// This might be an ok place for the NaN check.
return ({
title : g.attributes.title,
category : g.attributes.categoryid,
possible: g.attributes.possible
});
});
}
}
}
I'm lazy and didn't testing any of my code so reader beware. Also avoid the push method if possible. It can be a inefficient approach to append new elements onto an array.

Categories

Resources