Strings as keys of array - javascript

When using strings as keys of an array, console is showing that the array without these declared values and while iterating by this values where keys are string aren't displayed? , although i can get value of them.
>> var arr = [ 0, 1, 2, 3 ];
undefined
>> arr["something"] = "aught";
"aught"
>> arr
[0, 1, 2, 3]
>> arr["something"]
"aught"
>> for( var i = arr.length; i--; console.log( arr[ i ] ) );
3
2
1
0
I understand that arrays are objects which has implemented some kind of 'enumerate' interface in JavaScript's engine.
Most interesting is that interpreter isn't throwing either warning or error, so I spent some time of searching for where data could be lost.

In javascript there are 2 type of arrays: standard arrays and associative arrays
[ ] - standard array - 0 based integer indexes only
{ } - associative array - javascript objects where keys can be any strings
So when you define:
var arr = [ 0, 1, 2, 3 ];
you are defining a standard array where indexes can only be integers. When you do arr["something"] since something (which is what you use as index) is not an integer you are basically defining a property to the arr object (everything is object in javascript). But you are not adding an element to the standard array.

for( var i = arr.length; i--; console.log( arr[ i ] ) );
This will only give you the numeric indices, of course, but you can still loop over both numeric indices and string keys of your array like this:
for (var x in arr) {
console.log(x + ": " + arr[x]);
}
/* (console output):
0: 0
1: 1
2: 2
3: 3
something: aught
*/

Related

Sum of two multi dimensional array

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().

Giving string index with number

I was testing giving index as a string to array. But I noticed that array converts string index to number.
for example: A["1"] turns to with A[1]
Can I give a number as a string to array index?
A["1"] = 1;
A["3"] = 3;
expected output:
[ 1: 1, 3: 3 ]
output:
[ <1 empty item>, 1, <1 empty item>, 3 ]
like as usual string index arrays;
A["a"] = 1;
A["c"] = 3;
output:
[ a: 1, c: 3 ]
I think you are confusing objects and arrays.
An array is just a list of items:
const array = [1,2,3,4,5]
// You can access its items by index:
array[0] => 1
array['1'] => 2
An object is a list of key-value pairs and keys are strings:
const obj = { a: 1, b: 2 }
// You can access its item values by key:
array.a => 1
array['b'] => 2
All property names are strings, So array like numeric property names really aren't any different from any other property names.
Javascript arrays cannot have "string indexes". A Javascript Array is exclusively numerically indexed. When you set a "string index", you're setting a property of the object.
A.a = '1' and A['a'] = '1' are equals.
So I think you need to use object. You can do this to get the same output.
function test() {
// A["1"] = 1;
// A["3"] = 3;
let A = {
1: 1,
3: 3
};
return A;
}
output
{ '1': 1, '3': 3 }
Everything in JavaScript is an Object.
Array too. It's just has some special properties and notation. An array is an Object where values are stored in key value pair. Keys are index of an array and values are elements.
For example:
const a = [1,2,4,6]
Object.keys(a) // iterating through keys will give you indexes [0,1,2,3]
There is just one catch. If you provide index of an array as non negative Integer, it will push value to array else all values will be associated as object.
So
a["a"]=1 // [1,2,4,6, a:1], length of an array will be 4 and key a can be accessed as property
Hope it helps.

how do I repeatedly reorder array's elements without mutating the array itself?

I have array const arr = [1,2,3,4]
I want to get 4 different arrays by swapping a number pairs in this array.
I. e. the outcome of this array would be:
1st: [2,1,3,4]
2nd: [1,3,2,4]
3rd: [1,2,4,3]
4rd: [4,2,3,1] (swapping first and last elements)
I know Object.assign help's to avoid mutations but not sure how to implement it.
more explanation:
taking an original arr
swapping the first pair of numbers
returning [2,1,3,4]
repeating
taking an original arr
swapping the second pair of numbers
returning [1,3,2,4]
etc.
Looks like for any given array, you are going to produce an array of arrays characterized by single swaps. What's important to note is that this array of arrays has the same length (n) as the original array and that the ith array swaps elements i and (i+1)%n. Knowing that, here's a solution using map, Object.assign, and slice:
[ 1, 2, 3, 4 ].map( ( element, index, arr ) =>
Object.assign( arr.slice(), {
[ index ]: arr[ ( index + 1 ) % arr.length ],
[ ( index + 1 ) % arr.length ]: arr[ index ]
} ) );
Note element is unused.

Maintaining array order in Javascript

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)

Iteration over numeric Array in javascript returns strings

Why
for (i in [1, 2, 3]) console.log(typeof(i), i);
gives this:
[Log] string 0
[Log] string 1
[Log] string 2
I've expected numbers.
# Safari 7.0 (9537.71), Mac OS X 10.9
Try instead:
var arr = [1, 2, 3];
for (var i in arr)
console.log(typeof arr[i], arr[i]);
You're getting strings rather than numbers because for..in loops iterate keys/properties (in this case, the Array's indices) rather than values.
To get the value of each key, i, you'll have to use a property accessor, arr[i].
Though, why strings at all rather than the original number indices is because, with current standards, all properties are strings.
console.log(Object.keys( ['foo', 'bar', 'baz'] )); // ["0", "1", "2"]
Any value can actually be used with property accessors, but it'll be converted ToString() before it's actually used as a key/property.
6) Let propertyNameString be ToString(propertyNameValue).
Maps and Symbols are currently planned to be the exceptions to that.
Also, you may find "Why is using “for…in” with array iteration such a bad idea?" of interest and at least consider using a simple for loop instead:
var arr = [1, 2, 3];
for (var i = 0, l = arr.length; i < l; i++)
console.log(typeof arr[i], arr[i]);
Though, for future reference, the upcoming ECMAScript 6 standard has added for..of loops, which should iterate as you were expecting.
for (var i of [1, 2, 3])
console.log(typeof i, i); // number, 1, 2, 3
That is because an Array in Javascript is a special Object with property keys (which are strings) used as indices.
you are iterating that Array like an Object and because of that i is seen as a property key, a string.
To iterate in the right way an Array you have to use the following:
for( var i=0; i < [1,2,3].length; i++){ ... }

Categories