What is the purpose of spread syntax in this example? [duplicate] - javascript

This question already has answers here:
Why does spread syntax convert my string into an array?
(5 answers)
Closed 4 years ago.
Here,we created Hashmap with keys and value.Then we use array.map to get our result. i.e If we input "cat",we will get output as "dog".I didnt get how spread syntax is used.
var rule =
{
"c": "d",
"a": "o",
"t": "g",
"h": "a",
"e": "n",
"n": "t",
}
function output(str) {
return [...str].map(d => rule[d]).join('')
}
console.log(output('cat'))

Break it down:
[...str]
Gives: ['c', 'a', 't'];
In this case, the spread syntax breaks up the string into an array. Where each index represents a letter from the string.
.map(d => rule[d])
Converts the above array to:
['d', 'o', 'g']
As it goes through each value and uses the javascript object to get its value: (so 'c' maps to 'd' as rule['c'] = 'd', 'a' maps to 'o', etc...)
.join('')
Converts the above array to a string dog
Thus, doing:
console.log(output('cat'))
Gives: "dog"

spread syntax on a string turns it into an array consisting of its characters. This works because strings are iterable collections. http://es6-features.org/#SpreadOperator

In your case the spread operator spreads the string "cat" into an array of characters containing ['c','a','t']
Then it iterates over this array to provide the output string matches the values. There you get the string "dog" as output!

You would not be able to apply map to the string directly, as String does not have such a method. With the spread syntax you get an array of individual characters, and then map can be applied to that array.
It is in fact better practice to use Array.from instead, because it does not create the intermediate array and still allows you to execute a function on each character (using the second argument):
Array.from(str, d => rule[d]).join('')

It takes an iterable and returns each item of the iterable by using the spread syntax ....
In this case, a string is splitted to an array of characters.
['c', 'a', 't']
The same result could be achieved, if you use Array.from, which has a built-in mapping parameter.
var rule = { c: "d", a: "o", t: "g", h: "a", e: "n", n: "t" }
function output(str) {
return Array.from(str, d => rule[d]).join('');
}
console.log(output('cat')) ;

Related

Why can I not push a number into my array of strings even though I have converted the number back to a string?

Hello there I am trying to do a code wars kata: https://www.codewars.com/kata/54a91a4883a7de5d7800009c/train/javascript
I know what I have done is very long-winded but I wanted to do it step by step before I refactored it.
I have split the string input from the user
Filtered through the array just to get the number and converted it to a NUMBER
Incremented that number by 1
Changed number back to string
Now I want to add my string number to the original array but it doesn't work and I don't understand why :S
I know this is not the final answer to the kata but I am just trying things and wondered why this did not work...
function isNumeric(num){
return !isNaN(num)
}
function incrementString (string) {
const splitString = string.split("");
let numbers = Number(splitString.filter(el => isNumeric(el)).join("")); //[
'f', 'o', 'o', 'b',
'a', 'r', '0', '0',
'4', '2'
]
let incrementNumber = numbers +=1; // 43
let revertNumberToString = incrementNumber.toString(); // "43"
let test = splitString.push(revertNumberToString); // why can I not push the number 43 onto my original array?
console.log(test); // 11? why?
}
incrementString("foobar0042")
It does seem to be working correctly. If you check splitString again after you push to it then it will have all 11 items. That is where the number 11 is coming from. When you save a push to a variable it doesn't make a new array but rather it saves the length of the new array.
console.log(splitString)
// ["f", "o", "o", "b", "a", "r", "0", "0", "4", "2"]
let test = splitString.push(revertNumberToString);
console.log(splitString)
// ["f", "o", "o", "b", "a", "r", "0", "0", "4", "2", 43]
console.log(test); // 11? why?
Javascript push method adds the element to the array and returns the length, that's why you get 11 instead of the array itself. Reference
You could take a different approach by splitting the value into string and number part and take the length of the number part for later padding the value with leading zeroes.
function incrementString(value) {
const
string = (value.match(/\D+/) || [''])[0],
number = (value.match(/\d+/) || ['0'])[0];
return string + (+number + 1).toString().padStart(number.length, 0);
}
function assertEquals(a, b) {
console.log(a === b, a, b);
}
assertEquals(incrementString("foobar000"), "foobar001");
assertEquals(incrementString("foo"), "foo1");
assertEquals(incrementString("foobar001"), "foobar002");
assertEquals(incrementString("foobar99"), "foobar100");
assertEquals(incrementString("foobar099"), "foobar100");
assertEquals(incrementString(""), "1");

Access value "firstName" in object array [duplicate]

I have checked this page : mozilla documentation
I dont understand why the index 0 with :
const object3 = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.entries(object3)[0]);
// expected output: Array ["100", "a"] <== i thought of this
instead the documentation says you get :
// expected output: Array ["2", "b"]
Someone can explain it why ?
The Docs say that Object.entries returns an array of given objects enumerable property [key,value] pairs . So yes its confusing if you look at this statement
const object3 = { 100: 'a', 2: 'b', 7: 'c' };
and end up getting ["2", "b"] when you call Object.entries(object3)[0].
When you are doing this Object.entries(object3)[0] , you are accessing a pair at the index of 0 returned by this function Object.entries(object) . The order of this array has nothing to do with how you defined the object3 in the first place. The order according to the doc is the same as the provided by a
for...in loop. I ran the for...in loop on the object and this is what i got as the order.
2,7,100.
This is why you are getting ["2", "b"] instead of ["100", "a"]. As others have mentioned here , the order seems to be that way because 2<7<100.
This is because the object has numeric keys and when you manipulate the object with the numeric keys the javascript sort the key-values in ascending order of the key value and since you have keys 2, 7, and 100. So, check this when you console.log the object Object.entries(object3) you get that sorted and when you access [0] you get Array ["2", "b"]
const object3 = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.entries(object3));
Further clarification on sorting the object by ascending values of key when they are numeric. The javascript sorts them behind the scenes.
var a = {
10: 'ten',
5: 'five',
11: 'eleven',
1: 'one'
};
console.log(a);

Setting the value in a matrix after fill() returns incorrect matrix [duplicate]

This question already has answers here:
Array.prototype.fill() with object passes reference and not new instance
(7 answers)
Array.fill(Array) creates copies by references not by value [duplicate]
(3 answers)
Unexpected behavior using Array Map on an Array Initialized with Array Fill [duplicate]
(1 answer)
Closed 3 years ago.
If I initialize the matrix like
x = [["O", "O", "O"], ["O", "O", "O"], ["O", "O", "O"]];
And then set
x[0][1] = "X"
It returns
[ [ 'O', 'X', 'O' ], [ 'O', 'O', 'O' ], [ 'O', 'O', 'O' ] ]
as expected
However, if I initialize the matrix as the following:
x = new Array(3).fill(new Array(3).fill('O'))
And then
x[0][1] = "X"
It gives me back
[ [ 'O', 'X', 'O' ], [ 'O', 'X', 'O' ], [ 'O', 'X', 'O' ] ]
What is going on here?
When you do this:
x = [["O", "O", "O"], ["O", "O", "O"], ["O", "O", "O"]];
Javascript is creating 3 different Arrays in memory, so when you access x[0][1] you're accessing just that array.
When you are using the:
x = new Array(3).fill(new Array(3).fill('O'))
You are basically filling the array with same array 3 times, so when you access x[0][1] you're accessing the same Array in memory that's also connected to x[1] and x[2].
As commented by #Shidersz, a possible iterative solution would be:
// one liner:
Array.from({length: 3}, x => new Array(3).fill("0"));
This is creates an array and populates it with the values returned from the inputed function. Here's a breakdown:
// same as previous only longer with comments
// Create an Array from the first argument,
//as modified by the mapping function in the 2nd argument
Array.from(
// This could be any array like object.
// In the case of length it just reads the length property
// and iterates that number of times,
// so it could be useful if you want to
// fill the top array with 100000 arrays.
{length: 3},
// x argument for the mapping is irrelevant
x => {
// returning the array with 3 "0" strings in it.
return new Array(3).fill("0")
});
docs here for more reference.
The problem is that this line of code builds an array of three elements, where each element points to the same exact array:
x = new Array(3).fill(new Array(3).fill('O'))
To help explain, consider this example. Your code is essentially the same as this:
innerArray = new Array(3).fill('O');
x = [innerArray, innerArray, innerArray];
Note that each element is pointing to the same exact array. If you change the code to this instead, the array will behave the way you expect, because each element is a separate array:
x = [new Array(3).fill('O'), new Array(3).fill('O'), new Array(3).fill('O')];

guaranteed indexed object to array in order

extension of this question
So I was playing around with a project and I found myself needing to create a string where I didn't know the exact order of the lettering right away, but I did know their position(and by extension, the length of this string).
Part of the reason for doing it this way is that I don't want to skip array elements at any point during the process(NO ["a", , "t"] during the process). Meaning that the order of insertion matters.
let string_length = 10;
let o = {
0: "a",
4: "q",
7: "t",
3: "p",
6: "h",
1: "z",
2: "t",
5: "a",
9: "b",
8: "z"
};
function obj_to_arr(o) {
// this returns ["a","z","t","p","q","a","h","t","z","b"]
}
All the answers I've found until now don't necessarily guarantee that given an index object, it will give the corresponding ordered object, and this is mainly because of the nature of object, being unordered.
Is there a way to implement this?
You could fix this in two possible ways (and probably more).
Array
Either you add objects containing both the key and the value to an array.
array.push({c: "a"}) or array.push({ key: c, value: "a"}), then add the next and so on.
Push puts an element at the end of an array.
Sorted object
Or you insert into the object using alphabetic keys, in which case you can use the example below.
You could sort the keys (properties) of the object, and use them to access each value and put them into another array. Here's a verbose example of how you could do that.
const someObject = {
c: "a",
4: "q",
7: "t",
b: "p",
6: "h",
1: "z",
2: "t",
5: "a",
a: "b",
8: "z"
};
function obj_to_arr(obj) {
let result = []
// Get keys from object as an array
let keys = Object.keys(obj)
console.log('keys: ', keys)
// Sort the array in alphabetical order
let sorted = keys.sort()
console.log('sorted: ', sorted)
// Add each value to the resulting array
sorted.forEach(function(key) {
console.log('adding ' + obj[key] + ' to array')
result.push(obj[key])
})
console.log('result: ', result)
return result
}
// Call the function
obj_to_arr(someObject)
Using Object.keys(), you can retrieve an array of keys, sort them numerically, then map that sorted array to one with the values.
The result will be an array of values in an order corresponding to the numeric values of the keys, even if they are not sequential.
For example
let o = {"0":"a","1":"z","2":"t","3":"p","4":"q","5":"a","6":"h","7":"t","8":"z","10":"b"}
let sortedValues = Object.keys(o)
.sort((a, b) => a - b) // numeric comparison
.map(k => o[k]) // map to values
console.info(sortedValues)
The short answer is "you can't" because of the Javascript spec.
Objects in Javascript are not guaranteed to have their keys ordered in any way due it being a primitive type that engines are allowed to optimize the hell out of, including reordering keys to speed up property access.
If ordering really matters, then you shouldn't be using an object primitive. Either an array of tuples (which has guaranteed ordering):
let fixedList = [
{ key: 0, value: 'a' },
{ key: 4, vlaue: 'q' },
...
];
or you can use a Map, which exists specifically as a way to have "an object, with the same ordering of key/value pairs as you declared".
Of the two, for data transport you probably want the former, and for running code you typically want the latter.

Shorthand for creating an array of string values in javascript

Is there a quick way to create a literal array filled with strings in javascript?
I am coming from Ruby, where using %w{} allows for you to omit quotation marks and commas around the values of the array. For example:
array = %w{a b c}
=> ["a", "b", "c"]
is equivalent to the standard syntax for literal assignment:
array = ["a", "b", "c"]
=> ["a", "b", "c"]
Is there anything similar to this in javascript?
There may be a better way, but this would work:
var array = 'abc'.split(''); // ['a', 'b', 'c']
And for words:
var array = 'domo arigato mr. roboto'.split(' ');
// ['domo', 'arigato', 'mr.', 'roboto']
I don't know it's a proper way or not but I go with
'abc'.split(''); //returns array

Categories

Resources