var strArr = ["[1,2,3,4]","[1,2,3,4"]];
var arr1 = strArr[0].match(/\d+/g).map(Number);
I know that the map() method creates a new array with the results of calling a provided function on every element in the calling array. Here as Number is a wrapper object I am not able to understand what's going on.
What I understood is that if I console log removing the map method I get an array of strings whereas including the map method I get an array of numbers.I would like to know how map is able to take each string and converting to number.
var arr1 = strArr[0].match(/\d+/g).map(Number);
is equivalent to
var arr1 = strArr[0].match(/\d+/g).map((str, ind, arr) => Number(str, ind, arr));
The reason Number works despite passing extra arguments in is because it ignores everything but the first argument. You cannot expect every function to behave accordingly, since not all functions ignore everything but the first argument, but in this case it is a convenient shortcut. Another neat example that works well is converting truthy and falsy values to booleans:
var arrBool = arrAny.map(Boolean);
strArr[0] //selects the first string. "[1,2,3,4]"
.match(/\d+/g) // give an array of all continuos strings of digits. ['1','2','3','4']
.map(Number) // Calls Number on each value in the array (casting it to a number)
// and returns the array of results. [1,2,3,4]
//
// Keep in mind Number(val) attempts to create a Number from
// what ever is passed to it. If it is a string itll
// try to convert the string to a numerical value.
Its a complicated way of parsing a string containing an array literal. Seems like a complicated way of doing:
JSON.parse(strArr[0])
but without more context I cant tell you if its bad programming or if there is a good reason for it.
Actually Number is a function, and it can easily be proved:
typeof Number === 'function'; // true
Hence it can be used in any case where functions are expected (and naturally it can be passed as an argument):
Number("5") === 5; // true
let arr = ["442", "452h", "424", "foo", "bar", "31", "35"];
arr = arr.filter(x => !isNaN(Number(x))); // ["442", "424", "31", "35"]
And finally:
const arr2 = arr.map(x => Number(x)); // [442, 424, 31, 35]
const arr3 = arr.map(Number); // [442, 424, 31, 35] – the same result
UPD: To make it look extra-easy, let us compose a simple function that does exactly the same thing as the inbuilt Number function (converts values of other types to the number type):
const toNumber = x => +x;
// OR: function toNumber(x) { return +x; }
const arr4 = arr.map(toNumber); // also [442, 424, 31, 35]
You are passing in the Number object/function and converting a single thing that matches that regex in strArr into a Number
It's the same as doing Number(x), where x is an index in the array.
For example,
var num1 = "1";
var num2 = "2";
var result = Number(num1) + Number(num2); // This will work since they are both numbers now.
So calling map on the strings in the array just converts them that specific index into a Number object.
Learn more about Numbers here.
Related
Are there any substantial reasons why modifying Array.push() to return the object pushed rather than the length of the new array might be a bad idea?
I don't know if this has already been proposed or asked before; Google searches returned only a myriad number of questions related to the current functionality of Array.push().
Here's an example implementation of this functionality, feel free to correct it:
;(function() {
var _push = Array.prototype.push;
Array.prototype.push = function() {
return this[_push.apply(this, arguments) - 1];
}
}());
You would then be able to do something like this:
var someArray = [],
value = "hello world";
function someFunction(value, obj) {
obj["someKey"] = value;
}
someFunction(value, someArray.push({}));
Where someFunction modifies the object passed in as the second parameter, for example. Now the contents of someArray are [{"someKey": "hello world"}].
Are there any drawbacks to this approach?
See my detailed answer here
TLDR;
You can get the return value of the mutated array, when you instead add an element using array.concat[].
concat is a way of "adding" or "joining" two arrays together. The awesome thing about this method, is that it has a return value of the resultant array, so it can be chained.
newArray = oldArray.concat[newItem];
This also allows you to chain functions together
updatedArray = oldArray.filter((item) => {
item.id !== updatedItem.id).concat[updatedItem]};
Where item = {id: someID, value: someUpdatedValue}
The main thing to notice is, that you need to pass an array to concat.
So make sure that you put your value to be "pushed" inside a couple of square brackets, and you're good to go.
This will give you the functionality you expected from push()
You can use the + operator to "add" two arrays together, or by passing the arrays to join as parameters to concat().
let arrayAB = arrayA + arrayB;
let arrayCD = concat(arrayC, arrayD);
Note that by using the concat method, you can take advantage of "chaining" commands before and after concat.
Are there any substantial reasons why modifying Array.push() to return the object pushed rather than the length of the new array might be a bad idea?
Of course there is one: Other code will expect Array::push to behave as defined in the specification, i.e. to return the new length. And other developers will find your code incomprehensible if you did redefine builtin functions to behave unexpectedly.
At least choose a different name for the method.
You would then be able to do something like this: someFunction(value, someArray.push({}));
Uh, what? Yeah, my second point already strikes :-)
However, even if you didn't use push this does not get across what you want to do. The composition that you should express is "add an object which consist of a key and a value to an array". With a more functional style, let someFunction return this object, and you can write
var someArray = [],
value = "hello world";
function someFunction(value, obj) {
obj["someKey"] = value;
return obj;
}
someArray.push(someFunction(value, {}));
Just as a historical note -- There was an older version of JavaScript -- JavaScript version 1.2 -- that handled a number of array functions quite differently.
In particular to this question, Array.push did return the item, not the length of the array.
That said, 1.2 has been not been used for decades now -- but some very old references might still refer to this behavior.
http://web.archive.org/web/20010408055419/developer.netscape.com/docs/manuals/communicator/jsguide/js1_2.htm
By the coming of ES6, it is recommended to extend array class in the proper way , then , override push method :
class XArray extends Array {
push() {
super.push(...arguments);
return (arguments.length === 1) ? arguments[0] : arguments;
}
}
//---- Application
let list = [1, 3, 7,5];
list = new XArray(...list);
console.log(
'Push one item : ',list.push(4)
);
console.log(
'Push multi-items :', list.push(-9, 2)
);
console.log(
'Check length :' , list.length
)
Method push() returns the last element added, which makes it very inconvenient when creating short functions/reducers. Also, push() - is a rather archaic stuff in JS. On ahother hand we have spread operator [...] which is faster and does what you needs: it exactly returns an array.
// to concat arrays
const a = [1,2,3];
const b = [...a, 4, 5];
console.log(b) // [1, 2, 3, 4, 5];
// to concat and get a length
const arrA = [1,2,3,4,5];
const arrB = [6,7,8];
console.log([0, ...arrA, ...arrB, 9].length); // 10
// to reduce
const arr = ["red", "green", "blue"];
const liArr = arr.reduce( (acc,cur) => [...acc, `<li style='color:${cur}'>${cur}</li>`],[]);
console.log(liArr);
//[ "<li style='color:red'>red</li>",
//"<li style='color:green'>green</li>",
//"<li style='color:blue'>blue</li>" ]
var arr = [];
var element = Math.random();
assert(element === arr[arr.push(element)-1]);
How about doing someArray[someArray.length]={} instead of someArray.push({})? The value of an assignment is the value being assigned.
var someArray = [],
value = "hello world";
function someFunction(value, obj) {
obj["someKey"] = value;
}
someFunction(value, someArray[someArray.length]={});
console.log(someArray)
I have an array of array.
m = [[-100,100], [-100,-100], [-100,-100], [-100,100]]
And I want to remove the duplicates. I tried
aa = [...new Set(m)];
// and
let chkdup = (arr, tar) => tar.every(v => arr.includes(v))`.
But I can't remove the duplicates.
In Python, I can easily check this [-100,100] in m. But I don't know the function in JS. includes is not working for this case.
This happens because [-100, 100] != [-100, 100]. What you can do is convert the arrays into strings, and compare the strings instead, with JSON.stringify.
let m = [[-100,100], [-100,-100], [-100,-100], [-100,100]]
m = m.map(item => JSON.stringify(item).trim()) // Stringify everything (remove leading white space)
m = [...new Set(m)] // Convert to array getting rid of duplicates
m = m.map(item => JSON.parse(item)) // Parse it
Note that this is not very efficient (The interpreter has to convert into a string and parse the object again) but it is the simpliest solution. What it does is it checks if the JSON string of 2 Objects is equal an will not work with your own classes.
The reason why new Set doesn't work well is because in JavaScript, arrays with the same values are not equal. Try: console.log([-100,100] == [-100,100]); will return false. Please refer to this post if you simply wants to compare between arrays.
A workaround is to convert subarrays into strings, and use Set to deduplicate:
const arr = [
[-100, 100],
[-100, -100],
[-100, -100],
[-100, 100]
];
const setArray = new Set(arr.map(x => JSON.stringify(x)));
const result = [...setArray].map(x => JSON.parse(x));
console.log(result);
Using lodash uniq is a simple alternative.
You can simply do this thing using javascript Set , map then parse the value. For more information Map with Set
m = [[-100,100], [-100,-100], [-100,-100], [-100,100]];
result = Array.from(new Set(m.map(JSON.stringify)), JSON.parse);
console.log(t);
You can stringify your arrays using .map() with JSON.stringify(), and enter that into a set. Since you now have an array of strings, the set will remove the duplicates as it can check for equality correctly. You can then use Array.from with a mapping function of JSON.parse to convert it back into an array of arrays:
const m = [[-100,100], [-100,-100], [-100,-100], [-100,100]];
const res = Array.from(new Set(m.map(JSON.stringify)), JSON.parse);
console.log(res);
exercise:
Create a function that takes a number and returns an array of strings containing the number cut off at each digit.
examples:
420 should return ["4", "42", "420"];
2017 should return ["2", "20", "201", "2017"]
This is my code, how can I make it less more declarative? can`t find solution without push.
and yes it take me a lot of hours to try to resolve it in declarative way.thanks.
function createArrayOfTiers(num) {
arrT= num.toString().split("")
let z= []
const result = arrT.reduce((acc, curr)=>{
acc= acc+curr
z.push(acc)
return acc
},"")
return z;
}
PS: The input is guaranteed to be an integer in the range [0, 1000000]
You could get a string and return an array from it by using a closure which kees the previous characters.
Array.from works with an iterables, the string and the array has only a single character as value.
The following mapping takes a closure of an empty string. This closure returns a function for the mapping. v is an element of the array, like the standard Array#map callback.
Array.from(
number.toString(), // take iterables
(s => v => s += v)('') // map value of array with the previous elements
)
const getParts = number => Array.from(number.toString(), (s => v => s += v)(''));
console.log(getParts(2017));
I have got an array of the form:
['32 68', '56 78', '77 99']
I want to o/p another array which will contain the sum of each element in the index using JavaScript (NodeJS). Something like,
['100', '134', '176']
I tried to use .split("") but the double integer number again gets separated as separate digits. Is there any other way to solve this? Please not that, the i/p can be single digit number or double digit.
You'll want to get each item, split on a space (if exists) then add up the corresponding split. Something like this:
var origValues = ['32 68', '56 78', '77 99', '7'];
var addedValues = origValues.map(function(value) {
return value.split(' ')
.map(function(sArray) {
return parseInt(sArray);
})
.reduce(function(a, b) {
return a + b;
});
});
document.write(JSON.stringify(addedValues));
Note that this above example handles the case where you have a single digit inside your array value as well.
To provide some explanation as to what is happening...
You start off taking your original array and you are mapping a function on to each value which is what is passed into that function.
Inside that function, I am splitting the value by a space which will give me an array of (possibly) two values.
I then apply the map function again onto the array and parse each value in the array to an integer.
Last, I reduce the integer array with a summation function. Reduce applies an accumulator function to each item in the array from left to right so you will add up all your values. This result is returned all the way back up so you get your new array with your answers.
Kind of what it looks like in "drawing" form:
Start: origValues = ['32 68', '56 78', '77 99', '7']
Apply map (this will track one value): value = '32 68'
Apply the split: ['32', '68']
Map the parse integer function (I'm going to track both values): [32, 68]
Reduce: 32 + 68 = 100
I don't have time for an explanation (sorry) but, split + reduce will do it.
var arr = ['32 68', '56 78', '77 99'];
var sumArray = arr.map(function (s) {
return s.split(' ').reduce(function (a, b) {
return parseInt(a, 10) + parseInt(b);
});
});
document.write(JSON.stringify(sumArray));
You don't actually need map or anything. For each string we can .split, Numberify, and add.
secondArray[value] =
Number((firstArray[value].split(" "))[0]) +
Number((firstArray[value].split(" "))[1]);
Modifying this and turning this into a for loop, we get:
var arr2 = [];
for(var i = 0; i < arr.length; i ++){
arr2.push(
Number((arr[i].split(" "))[0]) +
Number((arr[i].split(" "))[1]));
}
arr = arr2;
Array1 = ['1,2,3']
How can I retrieve the numerical values by transforming it into non-string?
I've been trying parseInt, but I can only manage to get 1 as end-result.
Thanks.
If you start with an array containing a string, like in your example, you need to use split().
Example:
Array1 = ['1,2,3'];
var new_array = Array1[0].split(','); // new_array is ["1", "2", "3"]
for (var i = 0; i < new_array.length; i++) {
new_array[i] = parseInt(new_array[i]);
}
// new_array is now [1, 2, 3]
I would re-look why you're storing a comma separated string as an array element; but, if the reasoning is valid for your particular design, the question is do you have an array with more than one comma-separated string like this?
If you can, re-work your design to actually use an array of integers, so use:
var arr = [1,2,3];
instead of ['1,2,3'].
If you are storing comma separated strings as array elements, you can get each index as an array of integers using something like the following:
var array1 = ['1,2,3', '4,5,6,7'];
function as_int_array(list, index) {
return list[index].split(',').map(function(o) { return parseInt(o,10); });
}
console.log("2nd element: %o", as_int_array(array1, 1));
// => 2nd element: [4,5,6,7]
Hope that helps.
Generally parseInt() takes anything(most of the time string) as input and returns integer out of that input. If it doesn't get any integer then it returns NaN.
Why you are getting 1 !!!
Whenever you are using parseInt() it tries to read your input character by character. So according to your input
var Array1 = ['1,2,3'];
first it get's '1' and after that ',' (a comma, which is not a number) so it converts '1' into Integer and returns it as your result.
Solution of your problem :
var Array1 = ['1,2,3'];
//just displayed the first element of the array, use for or foreach to loop through all the elements of the array
alert(Array1[0].split(',')[0]);