Unexpected Output from Array() Method - javascript

I have this snippet of code below and don't quite understand the output
function repeatStringNumTimes(str, num) {
if (num <0) {
return ""
} else {
return Array(num+1).join(str)
}
}
console.log(repeatStringNumTimes("abc", 3));
I would have expected the output to be "abcabcabc" though if I console.log(repeatStringNumTimes("abc", 3)) in JS Bin it produces "abcabc"?
If I specify Array(3) - Would it not concatenate the string 3 times? Why only 2 in this instance?

If I specify Array(3) - Would it not concatenate the string 3 times?
Why only 2 in this instance?
console.log([1,2,3].join('abc'))
// outputs 1abc2abc3
Note that 'abc' is the separator for the join between the 3 elements, and so it appears twice, not 3 times.
Therefore, if you create an empty array, it shows 'abc' twice, separating 3 empty strings:
console.log(Array(3).join('abc'))
// outputs abcabc
Also note that there is String.repeat()
console.log('abc'.repeat(3))
// outputs abcabcabc

look when i run your code the right output appears so your code has no bugs, and when you specify Array(3) the output will be "abcabc" your code is working well

If you will have a look into the Array#join documentation, It will join the array items based on the passed separator in the join method. Ideally, It will not consider the join before the first and after the last element in an array.
console.log(Array(3)) // [undefined, undefined, undefined]
console.log([undefined, undefined, undefined].join('abc')); // 'abcabc'
As you want to fill the array with the string, Correct method is Array#fill which changes all elements in an array to a static value, from a start index (default 0) to an end index (default array.length) and then join the elements from an array with the help of Array.join() method.
console.log(Array(3).fill('abc').join(''));

Related

Pattern Matching in javascript returning true if first array has 2 and second array has 22 How do i solve this?

I have two arrays one of it is having user id and another one is having user ids. Those arrays are as follows.
1)The array which is having user id.
data[key].effective_employees Which is eaqual to [2].
Now I have another array which is having numbers of employee ids which is as follows.
data2[0].id Which is eaqual to [2,22,21].
And now I am trying to see whether the array two has number in array 1 I am using the following logic to see whether it is working or not.
if ((/^\d+$/.test(_.intersection([data2[0].id.toString()], data[key].effective_employees)))) {
let isElem = _.contains(returnStackFilterd, value);
if (isElem == false) {
returnStackFilterd.push(value);
}
} else {
returnStackFilterd = _.without(returnStackFilterd, value);
}
But this is showing true for the number 2 if the array two is having 22. Psudo code of what is happening with it is as follows.
if([2]is in[22,21]){ it is printing true} I want false here as the number two is not in the second array. The second array contains 22 and 21 which is not eaqual to 2
How do i solve this problem? The above psudo code should print false.
Let's break down your test expression and see why it doesn't work.
First off, we know that data[key].effective_employees is [2]. data2[0].id might be [2, 22, 21] or [22, 21]. If I'm understanding your question correctly, you want the whole test expression to return true in the first case and false in the second case.
Rebuilding your test expression from the bottom up, the innermost expression we find is this:
data2[0].id.toString()
This is a string with the value '2,22,21' or '22,21', depending on which case we are talking about. Next, you wrap this string in an array:
[data2[0].id.toString()]
So now we have ['2,22,21'] or ['22,21']. Note the quotes; in either case, it is an array with a single element that is a string.
Next, you take the intersection of this array with data[key].effective_employees, which we know is [2]:
_.intersection([data2[0].id.toString()], data[key].effective_employees)
So this expression is effectively
_.intersection(['2,22,21'], [2])
or
_.intersection(['22,21'], [2])
You are always taking the intersection of two arrays, where the first contains a single string and the second contains a number. They can't have any elements in common, so that's always going to produce an empty array ([]).
Finally, you test whether that empty array matches a regular expression:
/^\d+$/.test(_.intersection([data2[0].id.toString()], data[key].effective_employees))
// is effectively the same as
/^\d+$/.test([])
Regular expressions are supposed to be matched against a string, not an array. JavaScript is very lenient in situations like these and will coerce the value you're passing to a string. That means that the value [] is first converted to the empty string '' before being matched to the regular expression /^\d+$/. The empty string does not contain any digits, so this test always returns false.
This is why your test doesn't work as intended. However, let's take a few steps back, because you seem to be doing many things you don't need to do. Why convert arrays to strings (and then back to array)? Why match against a regular expression, if you just want to know whether two arrays have elements in common?
The following, simpler expression will give you the elements that data[key].effective_employees and data2[0].id have in common:
_.intersection(data[key].effective_employees, data2[0].id)
This will evaluate to either [2] or [], depending on whether data[key].effective_employees contains the number 2 or not.
I suggest saving the result of this expression to a variable, because it makes your code easier to read. Let's call it commonIds:
const commonIds = _.intersection(data[key].effective_employees, data2[0].id)
Now you can formulate different conditions, based on what exactly you want this intersection to be like. My impression is that you just want it to be nonempty (i.e., at least one element in common). In that case, you can compare its length to zero:
if (commonIds.length > 0) {
// code for when there is an overlap
} else {
// code for when there is no overlap
}
As a final note, I recommend assigning your base expressions data[key].effective_employees and data2[0].id to variables as well. Again, this makes your code more readable, and it also ensures that you need to change only one line of code if those base expressions change. Putting it all together:
const key = 'x';
const data = { [key]: {
effective_employees: [2],
}};
const data2 = [{
id: [2, 22, 21],
}];
const userId = data[key].effective_employees;
const employeeIds = data2[0].id;
const commonIds = _.intersection(userId, employeeIds);
if (commonIds.length > 0) {
console.log('userId appears in employeeIds');
} else {
console.log('userId does not appear in employeeIds');
}
<script src="https://underscorejs.org/underscore-umd-min.js"></script>
If data[key].effective_employees is the number 2, and data2[0].id is the array [2, 22, 21], the expression to test whether data2[0].id contains data[key].effective_employees is:
data2[0].id.includes(data[key].effective_employees)
From your original question, data2[0].id.toString() coerces the array to a string 2,22,21, which is no use to you. You also do not need to use Underscore for this.

A little bit confused with this javascript syntax --> arr.indexOf(searchElement[, fromIndex])

const beasts = ['ant', 'bison', 'camel', 'duck', 'bison'];
console.log(beasts.indexOf('bison'));
// expected output: 1
// start from index 2
console.log(beasts.indexOf('bison', 2));
// expected output: 4
console.log(beasts.indexOf('giraffe'));
// expected output: -1
I've been repeatedly looking at this js syntax. I've got this code from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf
It says that the fromIndex parameter is the index to start the search at. Now, from the code above, I'm confused about how the counting from the fromIndex parameter happens. From the code on the line:
// start from index 2
console.log(beasts.indexOf('bison', 2));
// expected output: 4
Camel is the item with index 2. How does the counting happen to arrive with an expected output of 4?
When I try to change the 2nd parameter,
// start from index 3
console.log(beasts.indexOf('bison', 3));
Duck is the item with index of 3. But the output that comes for indexOf('bison', 3) is still 4.
How does the counting really happen?
Nothing gets counted here, it just outputs you the index where the element is at.
If you type in console.log(beasts.indexOf('bison', 3)); then you start your search from index 3. You will still get 4 because bison is at index 4. Even the name indexOf says that you receive the index.
The array stays the same, just the starting point is moved to index 3
const beasts = ['ant', 'bison', 'camel', 'duck', 'bison'];
^
|
|
You start here and search to the right for "bison"
Very simple.
First element index is 0:
> console.log(beasts[0])
"ant"
indexOf will loop your array if you pass the second parameter.
In other words, if element was not found from the index you pass till its end, the command will continue looking for it from its beginning, continuing the counting.
It is not a matter of counting here. It's all about the position of an element in a zero-index based array.
Maybe you get confused because you get for the same word (bison) two indexes. No worry. Don't forget that that word is repeated twice in the array. Without even using indexOf you can see that it is in index 1 and index 4.

Vuex -- Help me understand the behavior of array findIndex

I'm having trouble with the following code (will explain after) within a Vue SPA component:
const accountArray = Array.from(Object.values(this.accounts)[0]) // [0 is the sub-array I need, and won't change]
const urlId = this.$route.params.id // 3
const i = accountArray.findIndex(account => account.id === urlId) // -1
console.log(i) // -1, as it didnt found any matches
console.log(urlId) // 3
The this.accounts is a computed property that returns an Observable object, and it works as expected (the 0 index is the sub-array of interest), hence my looping on it. The accountArray variable also returns the array that I want to iterate over (it has an account with id = 3), but when it comes to the iteration predicate, it ALWAYS returns -1 when it should be returning 2. Also, if I hard-code 3 instead of urlId, it returns the 2 that I'm looking for. Why?
When I print the accountArray, the output is the following:
I've made sure that this is not a Vuex reactivity problem, because I can refresh the page and it still returns me the arrays I need. What I'm missing here?
Thanks in advance!
You're using === comparison which expects the same value and same data type which is not true for your case. Your account.id is number and your urlId coming from route params is a string (3 !== "3").
Try converting route params id to a number before comparing it to account.id.
const urlId = +this.$route.params.id // 3
Notice + sign in front of this.$route.params.id used to convert a string to a number.
As an alternative, you could compare it using == which would return true for your 3 == "3" case, but I suggest you to stick to the first advice.

new Array(5).toString() returning four commas

to understand the below code snippet I looked at this link.
But still I am not able to figure it out why its printing four commas in the console.
since I am creating array of five items
can you tell me how its working.
new Array(5).toString();
",,,,"
Imagine what it would look like with values in each of the array indexes.
[1,2,3,4,5].join(); // Returns 1,2,3,4,5
Now if you remove the numbers, you're just left with the commas in the middle.
new Array(5).join(); // Returns ,,,, because the values are blank.
toString() method iterates throw all elements in the Array push them into string and push , betweeen them.
As you defined empty Array with 5 elements, when you apply toString it convert it to five "empty" strings with 4 "," between them
new Array(5)returns a sparse array or an array with 5 empty spaces inside. The only thing that this does is to set the length property of the array object to the specified argument (5 in this case).
console.log(new Array(5)) // browser console --> [empty × 5]
So naturally if you attempt to print its contents it would show you that you have 5 empty spaces separated by ,
console.log(new Array(5).toString()) // ,,,, <-- 5 empty ',' separated elements
As you can see, someArray.toString() will return what is inside the array but without [ and ].
console.log([1,2,3,4,5])
console.log([1,2,3,4,5].toString())
So, if you have noting in the array element, it will return empty string and only print the comma. (Array(5) is the same as [,,,,,])
console.log([,,,,])
console.log([,,,,].toString())
Array(5) will return an array only with the property length: 5. Wich will make it's elements undefined.
If you want to make it something else then undefined you can use .fill
console.log(Array(5))
console.log(Array(5).fill(""))
console.log(Array(5).fill("anything"))

Javascript - Reduce array of arrays

Array input: [["test","test"],["test2","test"],["test2","test2"],["test","test2"]]
Array output: ["test test","test2 test","test2 test2","test test2"]
I'm able to obtain this output with:
output = input.join("|").replace(/,/g," ").toString().split("|")
However, I don't really like this workaround because:
It seems unnatural
If one of the arrays contains a comma itself, it will be also
removed
If one of the arrays contains a pipe itself, the split will be not as expected
How can I get the output without those handicaps?
Instead of joining the outer array, you can use map to join each inner array separately:
var arr = [["test","test"],["test2","test"],["test2","test2"],["test","test2"]];
var output = arr.map(subarr => subarr.join(' '));

Categories