Related
I'm new in programming and I already have a little bit of background in Python.
At the moment, I'm studying Javascript and I was doing an exercise that should remove duplicate entries in an array.
I don't understand why the logic bellow doesn't work in JS, but works in Python. Can someone explain to me?
Javascript:
let array = [3, 3, 3, 4, 5];
let noRepetition = [];
for (let i of array) {
if (!(i in noRepetition)) {
noRepetition.push(i)
}
}
console.log('Before ', array);
console.log('After ', noRepetition);
Output:
Before [ 3, 3, 3, 4, 5 ]
After [ 3, 3, 3, 4, 5 ]
Python:
array = [3, 3, 3, 4, 5]
noRepetition = []
for i in array:
if not i in noRepetition:
noRepetition.append(i)
print(f'Before {array}')
print(f'After {noRepetition}')
Output:
Before [3, 3, 3, 4, 5]
After [3, 4, 5]
Actually, the in operator in javascript is not working as in python and checks keys (for an array, indexes).
> "a" in ["a", "b"]
false
> 1 in ["a", "b"]
true
> 2 in ["a", "b"]
false
You can use includes:
> ["a", "b"].includes("a")
true
And this should work as you expect.
You should also check libraries like lodash which provide a function for this.
Also you might want to consider using Sets if you want your data structure to be duplicate-free:
Array.from(new Set([2, 1, 3, 1]))
[ 2, 1, 3 ]
JavaScript: in operator parameters description:
A string or symbol representing a property name or array index (non-symbols will be coerced to strings).
which mean:
// Arrays
let trees = ['redwood', 'bay', 'cedar', 'oak', 'maple']
0 in trees // returns true
3 in trees // returns true
6 in trees // returns false
'bay' in trees // returns false (you must specify the index number, not the value at that index)
'length' in trees // returns true (length is an Array property)
Symbol.iterator in trees // returns true (arrays are iterable, works only in ES2015+)
// Predefined objects
'PI' in Math // returns true
// Custom objects
let mycar = {make: 'Honda', model: 'Accord', year: 1998}
'make' in mycar // returns true
'model' in mycar // returns true
in operator - JavaScript | MDN
I have an array that contains plenty of data. The format is always like that:
1:
UserName: "John Smith"
Priority: "2"
Time Occured: "02/09/2019 11:20:23"
Time Ended: "02/09/2019 11:20:23"
2:
UserName: "Tom Bill"
Priority: "4"
Time Occured: "01/08/2019 13:20:23"
Time Ended: "04/08/2019 15:20:23"
3:
UserName: "John Smith"
Priority: "2"
Time Occured: "06/08/2019 13:20:23"
Time Ended: "09/09/2019 15:20:23"
...
Then I am changing this one into json file but it always starts with:
[
null,
{
I am using JSON.stringify to make it work
result = JSON.stringify(array);
I have tried a few options, yet unfortunately it always ends with null at the beginning. Is there any way to remove the null from the beginning of the json, or maybe to replace it?
My advice would be to check why null is always the first item, but if you really can't change that, then you can use .shift() to remove the first element of the array before you stringify it:
const array = [null, 1, 2, 3, 4]
// this removes the first element
array.shift()
JSON.stringify(array)
>>> "[1, 2, 3, 4]"
We can also use this method to remove null, undefined, NaN, empty string from array use this code. This will filter the array. After filtering you can Stringify it:
Array=[null,1,2,3,null,4,undefined,7,NaN,"",8,]
// this removes the null,undefined,NaN,"" from this Array
var filtered = Array.filter(function(el) { return el; });
JSON.stringify(filtered)
console.log(filtered) //"[1, 2, 3, 4, 7, 8]"
I am trying to define a function, merge, which, when given two sorted arrays containing numbers, returns a sorted array of the numbers from both lists.
merge([ 4, 5, 6 ], [ 1, 2, 3, 4 ]) => [ 1, 2, 3, 4, 4, 5, 6 ]
merge([ 4 ], [ 2, 5, 8 ]) => [ 2, 4, 5, 8 ]
merge([ 1, 2, 6 ], []) => [ 1, 2, 6 ]
This is my code:
function merge(arr1, arr2) {
return arr1.concat(arr2).sort(arr1, arr2);
}
While the output is correct, I am told -- from my studies, and its automated tests -- that this code is not in good style. It writes:
Does not handles two arrays of same length.
Doesn't handle shorter first array.
Doesn't handle shorter second array.
What is a better way I can write this code? What should I do better?
Your code looks ok, however the way you're using sort is incorrect.
One way to use sort is to supply a function that compares two values in the array, and returns a number (positive or negative) to dictate the sorting of those values. For more information on sort, see this article
Consider the following changes to your merge method:
function merge(arr1, arr2) {
return arr1.concat(arr2).sort(function(valueA, valueB) { return valueA - valueB; );
}
Other answers already give you the literal answer of how to make your code correct. However, it is possibly missing the point. The function that you described is used in building a "merge sort", a very important sorting algorithm, whose major advantage is that it only needs to read the input lists once, sequentially, resulting in complexity of O(N) per pass; this allows it to even sort things that can't fit into the memory. Your code does not do that - it relies on sort, which is O(N log(N)) each time you invoke your function, and it doesn't utilise the fact that both its inputs are already pre-sorted (which is a key requirement for merge sort).
The merge sort algorithm will take the first element from both lists, then append the smaller one. Then it compares the next element from that list with the other list's first element, and again takes the smaller one. Repeat until one list is exhausted, then append the rest of the surviving list. (You can find a more exhaustive explanation of the merge sort on the Wikipedia page).
Amadan's answer paid attention to the problem constraints and pointed out that this can be written in O(n) time. Essentially, when inputs are both sorted, the algorithm is the "merge" step in a merge sort. This is done in linear time and works in a very simple and pleasing manner: look at the first item of each list and take the smaller of the two until one or both lists are exhausted. Then, tack any remaining elements onto the result array and return it.
The other answers are fine and in good JS style, but are in O(n log n) time and ignore entirely that the arrays are pre-sorted without mention, which is almost certainly not the answer someone asking for this routine would be looking for.
Here's a merge step:
const merge = (a, b) => {
const result = [];
while (a.length && b.length) {
result.push(a[0] < b[0] ? a.shift() : b.shift());
}
return result.concat(a).concat(b);
};
console.log(merge([ 4, 5, 6 ], [ 1, 2, 3, 4 ])); // => [ 1, 2, 3, 4, 4, 5, 6 ]
console.log(merge([ 4 ], [ 2, 5, 8 ])); // => [ 2, 4, 5, 8 ]
console.log(merge([ 1, 2, 6 ], [])); // => [ 1, 2, 6 ]
This can also be done with indexes which preserves the original arrays and is faster, but a little uglier-looking.
Here's a benchmark at JSPerf.
Just concat the arrays and return after applying a simple sort function:
console.log(merge([4, 5, 6], [1, 2, 3, 4])); //[ 1, 2, 3, 4, 4, 5, 6 ]
console.log(merge([4], [2, 5, 8])); //[ 2, 4, 5, 8 ]
console.log(merge([1, 2, 6], [])); //[ 1, 2, 6]
function merge(a, b) {
return a.concat(b).sort((a, b) => a - b);
}
I'm taking a coding challenge for linked lists in javascript. I haven't written a solution because I'm still trying to understand the basics.
Here's one of about 20 tests:
Input:
l: [3, 1, 2, 3, 4, 5]
k: 3
Expected Output:
[1, 2, 4, 5]
As a sort of hack to make sure I'm doing this right, I tried running the tests with this
function removeKFromList(l, k) {
return { value: 1, next: { value: 2, next: { value: 4, next: { value: 5, next: null}}}};
}
Returning a linked list... but it doesn't pass. Then I simply returned the array
function removeKFromList(l, k) {
return [1,2,4,5]
}
and it passed the first test.
Here's the question:
"Given a singly linked list of integers l and an integer k, remove all elements from list l that have a value equal to k."
My question is: Does l = [3, 1, 2, 3, 4, 5] count as a "linked list of integers"?
No, it doesn't, it's an array. However, it seems they're just giving the seed data, to leave the implementation (if you want) of the specifics of the linked list (along with seeding it) up to you completely. With that, means they need a uniform return which would be a 'seed' back to them (an array in order)
This is just out of curiosity, but do any of you have an idea why this code won't work?
[1, 2, 3, 4, 5].forEach(console.log);
// Prints 'Uncaught TypeError: Illegal invocation' in Chrome
On the other hand, this seems to work fine:
[1, 2, 3, 4, 5].forEach(function(n) { console.log(n) });
So... ?
It's worth pointing out that there is a difference in behavior in the implementation of console.log. Under node v0.10.19 you do not get an error; you simply see this:
> [1,2,3,4,5].forEach(console.log);
1 0 [ 1, 2, 3, 4, 5 ]
2 1 [ 1, 2, 3, 4, 5 ]
3 2 [ 1, 2, 3, 4, 5 ]
4 3 [ 1, 2, 3, 4, 5 ]
5 4 [ 1, 2, 3, 4, 5 ]
This is because the callback to forEach is a three-parameter function taking the value, the index, and the array itself. The function console.log sees those three parameters and dutifully logs them.
Under the Chrome browser console, however, you get
> [1,2,3,4,5].forEach(console.log);
TypeError: Illegal invocation
and in this case, bind will work:
> [1,2,3,4,5].forEach(console.log.bind(console));
1 0 [ 1, 2, 3, 4, 5 ]
2 1 [ 1, 2, 3, 4, 5 ]
3 2 [ 1, 2, 3, 4, 5 ]
4 3 [ 1, 2, 3, 4, 5 ]
5 4 [ 1, 2, 3, 4, 5 ]
but there is an alternative way: note that the second parameter to forEach takes the value of this to use in the callback:
> [1,2,3,4,5].forEach(console.log, console)
1 0 [ 1, 2, 3, 4, 5 ]
2 1 [ 1, 2, 3, 4, 5 ]
3 2 [ 1, 2, 3, 4, 5 ]
4 3 [ 1, 2, 3, 4, 5 ]
5 4 [ 1, 2, 3, 4, 5 ]
which works in the Chrome console and node for me. Of course, I'm sure what you want is just the values, so I'm afraid the best solution is, indeed:
> [1,2,3,4,5].forEach(function (e) {console.log(e)});
1
2
3
4
5
Whether node's behavior is a bug, or it simply takes advantage of the fact that console.log is not specified by ECMA is interesting in its own right. But the varying behavior, and the fact that you have to be aware of whether your callback uses this is important and means we have to fall back to direct coding, even if it is verbose thanks to the keyword function.
This works:
[1,2,3,4,5].forEach(console.log.bind(console));
Actually as #SLaks pointed out, console.log seems to be using this internally and when it's passed as a parameter this now refers to the array instance.
The workaround for that is simply:
var c = console.log.bind(console);
[1,2,3,4,5].forEach(c);
I can't say I've seen that syntax, but my guess is because log expects a parameter, being the message/object/etc to log in the console.
in the first example, you are just passing a function reference to forEach, which is fine if your function doesn't expect paramater which make the function behave as expected. In the second example you pass in e and then log it.