I have a array in JavaScript like this.
var arr=
[
['A'],[1,2,3,4],
['A'],[4,3,2,1],
['B'],[10,12,3,1],
['B'],[1,2,3,4],
.
.
.
.
['AZ'],[1,2,3,4]
]
and I want the output to summarize the array like -
var output=
[
['A'],[5,5,5,5],
['B'],[11,14,6,5],
['AZ'],[1,2,3,4]
]
Thanks.
Script
You can use the following script to achieve what you want to do.
const arr = [
["A"],
[1, 2, 3, 4],
["A"],
[4, 3, 2, 1],
["B"],
[10, 12, 3, 1],
["B"],
[1, 2, 3, 4],
["AZ"],
[1, 2, 3, 4],
];
/**
* Generator to return key-value pairs with array[i] being the key and array[i+1] being the value
* #param {Array<any>} array
*/
function* keyValue(array) {
// make sure we can build pairs (other ways of handling this are also possible)
if (array.length % 2 !== 0)
throw new RangeError(
"Array length must be dividable by 2 without remainder!"
);
for (let i = 0; i < array.length; i += 2) {
yield [array[i], array[i + 1]];
}
}
// here the created key-value pairs
console.log("Key-value pairs created by keyValue() generator function:");
console.log([...keyValue(arr)]);
// loop over key value pairs and sum up all the individul arrays based on the letter assigned to them
const result = [...keyValue(arr)].reduce((all, [[key], array]) => {
// if we don't have values for this letter, assing copy of the array to that letter
if (!all[key]) all[key] = [...array];
// we have some values for that letter already, sum up each value
else all[key] = all[key].map((prev, idx) => prev + array[idx]);
return all;
}, {});
// this would be a "better" result to my mind as there is no point wrapping single string values in arrays
// When using objects the values can easily be accessed in O(1)
console.log(result);
// now transform JS object to array of arrays
console.log("Result:");
const transformed = Object.entries(result).flatMap(([key, value]) => [[key], value]);
console.log(transformed);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Please note: This implementation assumes that the arrays for a given letter have the same length (as is the case in your example).
Explanation
First of all, I use a generator function keyValue() to always group two consecutive values in the array (a key and a value) together. One could also do this differently but once you understand how generators work that's an easy and elegant approach, I think. For this demo I just throw an error if the array is not dividable by 2 without remainder, but one could also handle this more gracefully.
Then, using reduce(), I iterate over the array created by using keyValue() and for each element in the array I check if I've encountered that value before. If I have not, I create a copy of the array (for immutablility) and assign it to the key i.e. a letter. If I have encountered a certain letter before I add up the values that I have previously saved assigned to that letter with the ones I am currently processing. After iteration all sums are calculated and I have a JavaScript object containing the results.
To my mind, this would be a good output because your output is a bit odd, since there is no point storing single letters in an array or even arrays of arrays. Using a JavaScript object is much more convenient and faster for lookups.
Nevertheless, you can easily deduct your result from the created object using flatMap().
Related
I'm trying to solve a coding challenge
it gives me an array and waits for the answer ,then gives me the next array and so on.
https://www.codewars.com/kata/5648b12ce68d9daa6b000099/train/javascript
I am trying to take this input: var busStops = [[10,0],[3,5],[5,8]] and return 5.
the code is supposed to add the first in each pair to a total while subtracting the second in each pair from the total eg: 10 - 0 + 3 - 5 + 5 - 8 = 5
First my code loops through the inner arrays and outer array ,pushing it into myarr as a regular array eg: [10,0,3,5,5,8].
It then adds the value if it is index is 0 or even and subtracts it if the index is odd.
This actually works!
Until it is given a second array eg: [[3,0],[9,1],[4,10],[12,2],[6,1],[7,10]]
It is still calculating the total correctly but is still remembering the total from the first array meaning it is returning 22 instead of 17
Why?
There is a var answer = 0 that is being executed ahead of the second loop
It should forget the value of the previous answer.
Right?
Edit: I figured out my problem. I just needed to empty myarr after the total was calculated!
let myarr = [];
var number = function (busStops) {
for (var i = 0; i < busStops.length; i++) {
for (var j = 0; j < busStops[i].length; j++) {
/*console.log(busStops[i][j]);*/
myarr.push(busStops[i][j]);
}
}
console.log("test");
var answer = 0;
console.log("test again");
for (let t = 0; t < myarr.length; t++) {
if (t == 0 || t % 2 == 0) {
answer = answer + myarr[t];
} else {
answer = answer - myarr[t];
}
}
console.log(answer);
return answer;
};
The task at your hand tries to somehow find a value (an integer) from an array of arrays (multidimensional array). That task seems to be reducing that multidimensional array into a single integer.
Luckily, JavaScript has some powerful array methods and one of them is the reduce method:
The reduce() method executes a user-supplied "reducer" callback function on each element of the array, in order, passing in the return value from the calculation on the preceding element. The final result of running the reducer across all elements of the array is a single value. Source: MDN
The reduce method tries to reduce an array's elements into a single value and in your case we want to reduce that multidimensional array into a single value that is the number persons who are still in the bus.
Before typing some code, let's dig a bit deeper into the reduce method:
It accepts 2 parameters, a callback function that acts as the reducer and the initial value to be used in the first iteration of the reduce method.
The reducer callback function, on its own, accepts 4 parameters that are supplied by the reduce method. You may learn more about those parameters here as am only going to focus on the first 2 parameters the reducer accepts:
previousValue: hold the value from the previous reducer call. On first call, it contains the value you set to the initial value parameter of the reduce method or, if you didn't supply an initial value, previousValue shall hold the value of your array's first element (arr[0]).
currentValue: hold the current reduce iteration's item.
Now, let's get back to the task we have, we need to calculate the number of persons who are still in the bus based on a supplied multidimensional array. Each item in that multidimensional array is an array of two values where the result we need at the end is: the sum of the differences between each array, in the multidimensional array, first and second values (sum = multiDim[i][0] - multiDim[i][1] + multiDim[i + 1][0] + multiDim[i + 1][1] etc...).
To solve this task, we'll reduce that multidimensional array into a single number (let's call it result) by using a simple reducer function that will start by an initial value of 0 (as we're calculating a sum in our case) and will add, to the result, the difference between the first and the second values of the array supplied by the reduce at each iteration.
To illustrate, here's a live demo:
/**
* a function that calculates and returns the number of person who are still in the bus or precisely, the sum of the differences between "c[0]" and "c[1]"
* busArray: the supplied multidimensional array to reduce
* the reducer accepts two parameters:
* r: the result from the last call to the reducer function (initially set to 0, the initial value (see second parameter passed to the "reduce" method))
c: hold the current iteration's array.
*/
const calculateWhoAreInTheBus = busArray => busArray.reduce((r, c) => r += c[0] - c[1], 0);
/** test the created "calculateWhoAreInTheBus" function */
console.log(calculateWhoAreInTheBus([
[10, 0],
[3, 5],
[5, 8]
])); // should print: 5
console.log(calculateWhoAreInTheBus([
[3, 0],
[9, 1],
[4, 10],
[12, 2],
[6, 1],
[7, 10]
])); // should print: 17
console.log(calculateWhoAreInTheBus([
[3, 0],
[9, 1],
[4, 8],
[12, 2],
[6, 1],
[7, 8]
])); // should print: 21
console.log(calculateWhoAreInTheBus([
[0, 0],
[0, 0]
])); // should print: 0
I would advice you to use Array.prototype.reduce instead. For example like this:
const reducer = (previous, current) => previous + current[0] - current[1];
const answer = busStops.reduce(reducer, 0);
It is very brief (although this is not a goal in and of itself) and the reducer function does almost trivial work, so it does not complicate unneccesarily. Best of all it encapsulates the functionality with a minimal need of extra variables.
Othwerwise you could simplify your function a bit but use the let keyword to keep variables locked to scope like:
function number(busStops) {
let answer = 0;
for (let bs of busStops) {
answer += bs[0] - bs[1];
}
return answer;
}
Who can kindly explain the accumulator acc construction below in plain English?
return arr1.reduce(function(acc, curr){
var last = acc[acc.length-1];
if(acc.length > 0 && curr[1]===last[1]) {
last[0] += curr[0];
} else acc.push(curr);
return acc;
}, []);
}
This reduce method can be used to solve the FreeCodeCamp "Inventory Update" assignment, as part of their advanced algorithm scripting lessons.
One is required to update existing items in an inventory array (arr1) with new items in a "new delivery" array.
Two test arrays, a present inventory curInv and a new delivery newInv respectively, could be as follows:
var curInv = [
[21, "Bowling Ball"],
[2, "Dirty Sock"],
[1, "Hair Pin"],
[5, "Microphone"]
];
var newInv = [
[2, "Hair Pin"],
[3, "Half-Eaten Apple"],
[67, "Bowling Ball"],
[7, "Toothpaste"]
];
After finding several excellent articles on Javascript reduce method (such this post and a great video course on egghead.io), and somehow sensing the power it is harnassing, I would read the method as follows:
Reduce the inventory array, by creating an empty array [ ] first (the initial value), then applying the following callback function:
If the inventory array is currently not empty (has a length greater than zero), and the name of currently handled item (index 0 of curr could read "Bowling Ball" for example) is identical to the last item of the inventory array being updated, then update the amount of this item in the inventory array.
The last item is defined right above the if statement, as follows: take the present length of the accumulated array upto now, subtract 1, and use this value to index the accumulated array. The element at that index is then assigned to the variable 'last'.
On the other hand, if the inventory is empty, add the new item entirely, - that is: item name and amount.
Now return the newly accumulated array."*
How is using the length - 1 of the accumulator useful to make acc actually accumulate?
(pardon the alliteration)
I think I understand most of how this reduce method is built, but please correct me wherever I'm misreading), except this particular
use of acc.length-1.
Cheers, k.
The actual solution involves concatenating and sorting both arrays and only then reducing them.
In this case whenever we evaluate a new item, if its name is not equal to the last accumulator item, it means it's a new item.
Using your example, the list we are reducing is:
[
[ 21, 'Bowling Ball' ],
[ 67, 'Bowling Ball' ],
[ 2, 'Dirty Sock' ],
[ 1, 'Hair Pin' ],
[ 2, 'Hair Pin' ],
[ 3, 'Half-Eaten Apple' ],
[ 5, 'Microphone' ],
[ 7, 'Toothpaste' ]
]
so when we encounter the second item, the last value in the accumulator is [21, 'Boweling Ball'] and when we compare the strings we go into the first condition.
Are you asking about this section?
var last = acc[acc.length-1];
If so acc.length-1 is so because in an array
acc = [a,b,c,d]
acc.length is equal to 4
to access element d you will access it via
acc[3]; //which equals d
That is because we count positions from 0,1,2,3
tl;dr: Check out this REPL example
Reduce is capable of reducing the original array to a value that is defined on the function.
For instance, if we had an array of integers that we wanted to compute the total sum of it, we could use reduce to achieve that.
Of course, you might ask why would you ever want to use reduce as opposed to a for loop?
The primary reason why reduce is a better choice is because the reducer function that we pass as a parameter is pure. That means, there are no 'extra' nor 'external' variables that are needed in order to compute the result. In a for loop, we would need to have a totalSum variable to compute the result, whereas in the reduce version this is not needed.
Back to the OP's example, this is how we could construct the reduce to group by the invites by the same names:
// reduce example
const reducer = (accumulator, currentValue) => {
if (accumulator.length === 0) {
accumulator.push(currentValue);
return accumulator;
}
const index = accumulator.findIndex(el => el[1] === currentValue[1]);
if (index !== -1) {
accumulator[index][0] += currentValue[0];
return accumulator;
}
accumulator.push(currentValue);
return accumulator
};
Here's the equivalent version with the for loop:
// for loop example
let withForLoop = (input) => {
let res = [];
for (let i = 0; i < input.length; i++) {
let currInput = input[i];
const index = res.findIndex(el => el[1] === currInput[1]);
if (index !== -1) {
res[index][0] += currInput[0];
continue;
}
res.push(currInput);
}
return res;
}
If you are new to reduce, it might take some time until you completely understand it. Its usage almost always leads to less bug-prone applications, thus I would advocate for taking some time to fully understand its capabilities and when to use it.
I'm trying to solve a freeCodeCamp exercise with this goal:
Write a function that takes two or more arrays and returns a new array
of unique values in the order of the original provided arrays.
In other words, all values present from all arrays should be included
in their original order, but with no duplicates in the final array.
The unique numbers should be sorted by their original order, but the
final array should not be sorted in numerical order.
So what I do is concatenate all the arguments into a single array called everything. I then search the array for duplicates, then search the arguments for these duplicates and .splice() them out.
So far everything works as expected, but the last number of the last argument does not get removed and I can't really figure out why.
Can anybody please point out what I'm doing wrong? Please keep in mind that I'm trying to learn, so obvious things probably won't be obvious to me and need to be pointed out. Thanks in advance.
function unite(arr1, arr2, arr3) {
var everything = [];
//concat all arrays except the first one
for(var x = 0; x < arguments.length; x++) {
for(var y = 0; y < arguments[x].length; y++) {
everything.push(arguments[x][y]);
}
}
//function that returns duplicates
function returnUnique(arr) {
return arr.reduce(function(dupes, val, i) {
if (arr.indexOf(val) !== i && dupes.indexOf(val) === -1) {
dupes.push(val);
}
return dupes;
}, []);
}
//return duplicates
var dupes = returnUnique(everything);
//remove duplicates from all arguments except the first one
for(var n = 1; n < arguments.length; n++) {
for(var m = 0; m < dupes.length; m++) {
if(arguments[n].hasOwnProperty(dupes[m])) {
arguments[n].splice(arguments[n].indexOf(dupes[m]), 1);
}
}
}
//return concatenation of the reduced arguments
return arr1.concat(arr2).concat(arr3);
}
//this returns [1, 3, 2, 5, 4, 2]
unite([1, 3, 2], [5, 2, 1, 4], [2, 1]);
Looks like you overcomplicated it a bit ;)
function unite() {
return [].concat.apply([], arguments).filter(function(elem, index, self) {
return self.indexOf(elem) === index;
});
}
res = unite([1, 2, 3], [5, 2, 1, 4], [2, 1], [6, 7, 8]);
document.write('<pre>'+JSON.stringify(res));
Explanations
We split the problem into two steps:
combine arguments into one big array
remove non-unique elements from this big array
This part handles the first step:
[].concat.apply([], arguments)
The built-in method someArray.concat(array1, array2 etc) appends given arrays to the target. For example,
[1,2,3].concat([4,5],[6],[7,8]) == [1,2,3,4,5,6,7,8]
If our function had fixed arguments, we could call concat directly:
function unite(array1, array2, array3) {
var combined = [].concat(array1, array2, array3);
// or
var combined = array1.concat(array2, array3);
but as we don't know how many args we're going to receive, we have to use apply.
someFunction.apply(thisObject, [arg1, arg2, etc])
is the same as
thisObject.someFunction(arg1, arg2, etc)
so the above line
var combined = [].concat(array1, array2, array3);
can be written as
var combined = concat.apply([], [array1, array2, array3]);
or simply
var combined = concat.apply([], arguments);
where arguments is a special array-like object that contains all function arguments (actual parameters).
Actually, last two lines are not going to work, because concat isn't a plain function, it's a method of Array objects and therefore a member of Array.prototype structure. We have to tell the JS engine where to find concat. We can use Array.prototype directly:
var combined = Array.prototype.concat.apply([], arguments);
or create a new, unrelated, array object and pull concat from there:
var combined = [].concat.apply([], arguments);
This prototype method is slightly more efficient (since we're not creating a dummy object), but also more verbose.
Anyways, the first step is now complete. To eliminate duplicates, we use the following method:
combined.filter(function(elem, index) {
return combined.indexOf(elem) === index;
})
For explanations and alternatives see this post.
Finally, we get rid of the temporary variable (combined) and chain "combine" and "dedupe" calls together:
return [].concat.apply([], arguments).filter(function(elem, index, self) {
return self.indexOf(elem) === index;
});
using the 3rd argument ("this array") of filter because we don't have a variable anymore.
Simple, isn't it? ;) Let us know if you have questions.
Finally, a small exercise if you're interested:
Write combine and dedupe as separate functions. Create a function compose that takes two functions a and b and returns a new function that runs these functions in reverse order, so that compose(a,b)(argument) will be the same as b(a(argument)). Replace the above definition of unite with unite = compose(combine, dedupe) and make sure it works exactly the same.
You can also try this :
var Data = [[1, 2, 3], [5, 2, 1, 4], [2, 1], [6, 7, 8]]
var UniqueValues = []
for (var i = 0; i < Data.length; i++) {
UniqueValues = [...new Set(UniqueValues.concat(Data[i]))]
}
console.log(UniqueValues)
I'm reading a book called Eloquent JavaScript. There's an exercise in it that requires one to flatten a heterogeneous array & after trying so long and failing to get the answer, I looked up the solution online & couldn't understand the code. I'm hoping someone will be kind enough to explain, especially for argument "flat" and how it's supposed to work. The code is below
var arrays = [[1, 2, 3], [4, 5], [6]];
console.log(arrays.reduce(function(flat, current) {
return flat.concat(current);
}, []));
The reduce function defined in the book is:
function reduce(array, combine, start) {
var current = start;
for (var i = 0; i < array.length; i++)
current = combine(current, array[i]);
return current;
}
and as a method of an array,
arr.reduce(combine, start);
Let's look at each part of the reduce method. The book describes it as "folding up the array, one element at a time." The first argument for reduce is the "combiner function", that accepts two arguments, the "current" value and the "next" item in the array.
Now, the initial "current" value is given as the second argument of the reduce function, and in the solution of flattening arrays, it is the empty array, []. Note that in the beginning, the "next" item in the array is the 0th item.
Quoting the book to observe: "If your array contains at least one element, you are allowed to leave off the start argument."
It may also be confusing that in the flattening solution, current is placed as the second argument to reduce, whereas in the reduce definition above, current is used to assign the cumulative, folded value. In the flattening solution, current refers to the "next" arrays item (the individual array of integers)
Now, at each step of the reduction, the "current" value plus the next array item is fed to the (anonymous) combiner, and the return value becomes the updated "current" value. That is, we consumed an element of the array and continue with the next item.
flat is merely the name given to the accumulated result. Because we wish to return a flat array, it is an appropriate name. Because an array has the concat function, the first step of the reduce function is, (pretending that I can assign the internal variables)
flat = []; // (assignment by being the second argument to reduce)
Now, walk through the reduction as iterating over arrays, by going through the steps shown above in reduce's definition
for (var i = 0; i < arrays.length; i++)
flat = combine(flat, arrays[i]);
Calling combine gives [].concat([1, 2, 3]) // => [1, 2, 3]
Then,
flat = [1, 2, 3].concat([4, 5]) // => [1, 2, 3, 4, 5]
and again for the next iteration of the reduction. The final return value of the reduce function is then the final value of flat.
This would be the solution I came with with ES6 format:
const reduced = arrays.reduce((result,array) => result.concat(array),[]);
console.log(reduced);
I have implemented this solution and this seems to work for nested arrays as well.
function flattenArray(arr){
for(var i=0;i<arr.length;i++){
if(arr[i] instanceof Array){
Array.prototype.splice.apply(arr,[i,1].concat(arr[i]))
}
}
return arr;
}
There is an easy way to do these exercises. those functions are already built inside the javascript so you can use them easily.
But the whole joy of this exercise is to create those functions:
Create reduce function. Reduce function should add all array elements. you can use a higher-order function or just a normal one. here is an example for higher-order:
function reduce(array, calculate){
let sumOfElements = 0;
for(let element of array){
sumOfElements = calculate(sumOfElements, element)
}
return sumOfElements
}
Next step is to create a concat function. since we need to return those reduced arrays in new array we will just return them. (Warning: you must use rest parameter)
function concat(...arr){
return arr
}
And for last. you will just display it (You can use any example)
console.log(concat(reduce([1, 2, 3, 4], (a, b) => a + b), reduce([5, 6], (a, b) => a + b)))
The reduce method acts as a for loop iterating over each element in an array. The solution takes each array element and concatenates it to the next one. That should flatten the array.
var arr =[[1,2],[3,4],[5,6]]
function flatten(arr){
const flat= arr.reduce((accumulator,currentValue)=>{
return accumulator.concat(currentValue)
})
return flat
}
console.log(flatten(arr))
//Output 1,2,3,4,5,6
I am new to JavaScript and I am having trouble working with my array, I want my array ordered how I explicitly write it and not how JavaScript decides it wants it.
If we have a array
var array = {
0: 'zero',
4: 'four',
2: 'two'
};
When I choose to display this in the console, or iterate over it, Its reordered like this
array = {
0: 'zero',
2: 'two',
4: 'four'
};
I have tried 2 loops so far, The for loop, and also the for loop with the in statement.
Both work according how I assumed they would as they use a key and work there way up/down, making order I specify is absolutely useless.
How can I write/print/work with my array as its ordered, In other languages such as PHP its as simple as
$array = array(
0 => 'zero',
4 => 'four',
2 => 'two'
);
foreach($array as $key => $value)
echo $key ."\n";
This would output
0
4
2
Thanks in advance.
You're using an object {}, not an array []. Objects have no explicit order, where Arrays do. That's why you're having your problem. Change your {} to [] and you'll be fine. You could even use an array of objects.
var array = [
{0: 'zero'},
{4: 'four'},
{2: 'two'}
];
Looping over that like so
for(var i = 0; i < array.length; i++){
console.log(array[i]);
}
Gives us our normal order.
Object {0: "zero"}
Object {4: "four"}
Object {2: "two"}
Another Edit: The problem is you're trying to have an array that has properties and values just like an object, without using an object, {property: value} - that can't really be done with an array. To loop over an array like you want, it's as simple as
var arr = [1,2,3]
and
for(var i = 0; i < arr.length; i++){
console.log(i) //1,2,3
}
but the problem, like mentioned above, is you want more complex arrays which you simply can't do.
You need to understand what an Array and what an Object are, they are fundamentally different things and do not behave the same.
Array
Arrays are list-like objects whose prototype has methods to perform traversal and mutation operations. Neither the length of a JavaScript array nor the types of its elements are fixed. Since an array's size length grow or shrink at any time, JavaScript arrays are not guaranteed to be dense. In general, these are convenient characteristics; but if these features are not desirable for your particular use, you might consider using typed arrays.
Examples of an Array, note the magical length property, the values assigned to an Array are always found at their indexed locations; index is from 0 to 2^32 - 1
// dense arrays
var array1 = [1, 2, 3];
array1.length === 3;
array1[0] === 1;
var array2 = [];
array2[0] = 1;
array2[1] = 2;
array2[2] = 3;
array2.length === 3;
array1[1] === 2;
var array3 = [];
array3.push(1);
array3.push(2);
array3.push(3);
array3.length === 3;
array3[2] === 3;
// and a sparse array
var array4 = [];
array4[0] = 1;
array4[2] = 2;
array4[4] = 3;
array4.length === 5;
array4[1] === undefined;
Iterating an array for
var array = [1, 2, 3, 4, 5];
for (var index = 0; index < array.length; index += 1) { // counts from (index) 0 to 4
console.log(index, array[index]); // outputs 0 1 \n 1 2 \n 2 3 \n 3 4 \n 4 5
}
Object
An object is a collection of properties, and a property is an association between a name and a value. A property's value can be a function, in which case the property is known as a method. In addition to objects that are predefined in the browser, you can define your own objects.
Examples of an Object, there is no magical length property.
var object1 = {
'zero': 1,
'one': 2,
'two': 3
};
object1.zero === 1;
var object2 = {);
object2['zero'] = 1;
object2['one'] = 2;
object2['two'] = 3;
object2.one === 2;
var object3 = {);
object3.zero = 1;
object3.one = 2;
object3.two = 3;
object['two'] === 3;
Iterating (enumerating) an object for..in
var object = {
one: 0,
two: 1,
three: 2
};
for (var property in object) {
if (object.hasOwnProperty(property)) { // make sure the property belongs to object
console.log(property, object[property]); // outputs (not necessarily this order)
// three 2 \n two 1 \n one 0
}
};
If you are trying to maintain an ordered Object, then this is not how Javascript works and iteration (enumeration) of an object is arbitrary. There are techniques that you can use to iterate (enumerate) an Object in a known order. This requires that you keep an ordered list of properties in an array and use the array in the iteration process.
var object = {
'c': 1,
'z': 2,
'b': 3,
'a': 4
}
var propertyOrder = ['c', 'z', 'b', 'a'];
for (var index = 0; index < propertyOrder.length; index += 1) {
console.log(index, propertyOrder[index], object[propertyOrder[index]]); // outputs 0 c 1 \n 1 z 2 \n 2 b 3 \n 3 a 4
}
I don't get it. What makes you think that 0, then 4, then 2, is in any form or shape "in order"?
However, apparently what you want is to keep the number and the string together, in the order that you specify.
Your mistake, if you'll excuse me for perhaps sounding a bit harsh, is that you seem to think that you can use indices or member names to be both a means to access data and part of the data itself.
You can't, and you shouldn't. An index is an index, a name is a name, and data is data [1].
Here are two implementations of keeping your numbers and strings together:
var pairs = [
[0, "zero"],
[4, "four"],
[2, "two"]
];
for (var index in pairs) {
alert(pairs[index][0] + ": " + pairs[index][1]);
};
For this one, I keep the pairs of numbers and strings together in arrays of their own: the numbers at position 0, the strings at position 1. I store these arrays in pairs.
Then I iterate over array with for/in, which, in each iteration, gives me an index of my pairs array.
I then use that index to access the right sub-array in pairs, and get the number from position 0 and the string from position 1.
var pairs = [
{number: 0, string: "zero"},
{number: 4, string: "four"},
{number: 2, string: "two"}
];
for (var index in pairs) {
alert(pairs[index].number + ": " + pairs[index].string);
};
This one works exactly the same, except of storing the pairs in arrays, I store them in objects.
This has the added bonus of better readability inside the for loop: pairs[index][0] and pairs[index][1] do not really convey a clear meaning. It tells us nothing more than, "of the pair with the given index, get items 0 and 1".
However, pairs[index].number and pairs[index].name are much clearer: "of the pair with the given index, give me the number and the name."
_
Footnotes:
[1a] A number is a number: my bank account number is just that: a means to identify my bank account. It doesn't convey any meaning as to my name, my PIN, or the balance on my account -- all attributes that would qualify as data belonging to my bank account.
[1b] A name is a name: my name is just a name. When you're talking about me, you can use my name to refer to me, so that others know whom you are talking about. My name does not convey any information about my hobbies, my SSN, or what brand of car I have -- all attributes that would qualify as data that would describe certain aspects of me. (However, by convention, you can often tell a person's gender by their name)