Why doesn't my linked list output pass this test? - javascript

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)

Related

Why array loops works in Python to remove duplicated entries, but JS don't?

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

Is there a way to ensure javascript object properties are ordered in a specific way?

I have a JavaScript object that looks like this:
Const data = {
x: 1,
y: 2,
z: 3
a: 4,
b: 5,
c: 6
};
We have a signing service in our Angular 6 application which stringifies this object, hashes the string, then attached a signature to it. Then it saves it to a firestore database. The database likes to order the properties alphabetically so it ends up looking like this:
{
a: 4,
b: 5,
c: 6,
x: 1,
y: 2,
z: 3
}
When we retrieve this object from the database and try to validate the signature, it fails. It fails because when you stringify this object, the alphabetical order of the properties results in a different string compared to when we signed it. This results in a different hash which doesn’t match with the original signature.
Our current solution to this problem is that we write out the order of the properties alphabetically in the code, but we’d like to make this fool proof (ex. If another developer comes along and adds a property to the bottom, say d, not realizing it’s supposed to be alphabetical). I’m told by a colleague that there is some way of telling Javascript to order the properties according to its own algorithm. If we could do that, then we’d order the properties according to that algorithm before stringifying, hashing, and signing, and then when we retrieve the object from the database, do the same thing: order the properties according to Javascript’s algorithm, stringify, hash, and validate.
Does anyone know what this Javascript ordering is and how to do it?
There isn't a way for JS to naturally order an object, you're going to have to tinker with it yourself.
The easiest way that I can think of to do this would be to use an array and sort from there.
This will return you the following array...
Object.entries(test).sort((a, b) => a[1] - b[1])
returns
[ [ 'x', 1 ],
[ 'y', 2 ],
[ 'z', 3 ],
[ 'a', 4 ],
[ 'b', 5 ],
[ 'c', 6 ] ]
If you want it back in an object,
Object.assign({}, ...Object.entries(test).sort((a, b) => a[1] - b[1]).map(([key, value]) => ({[key]: value})) )
returns
{ x: 1, y: 2, z: 3, a: 4, b: 5, c: 6 }
Create a custom stringify function that handles putting the object in the correct order.
const data = {
a: 4,
b: 5,
c: 6,
x: 1,
y: 2,
z: 3
}
function customStringify(d){
return '{'+Object
.entries(d)
.sort(([,v1],[,v2])=>v1-v2)
.map(([k,v])=>`${k}:${v}`)
.join(",")+'}';
}
const res = customStringify(data);
console.log(res);

Making a function returning assorted arrays?

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);
}

Angular Controls/ generating array from number

I have a number in my application value is 6,
by using this value i have to create an array of [1, 2, 3, 4, 5, 6] using javascript/typescript
i have tried this in my application
this.builder.group({
'staff': this.builder.group({
staff: [false],
id: [this.staffData[i].users[j].id],
labelName: [this.staffData[i].users[j].name],
controlname: ['staff'],
cssclass: ['error'],
checked: [false],
customcss: ['test1'],
dayid: this.selectedDay,
number: Array(this.appointmentsData.numberofSlots).fill().map((x,i) => i)})
})
but i am getting number as 0 in browser console.
in VSCode also it is showing excepted 1-3 arguments but got 0 (i think it is for fill() method as i am passing 0 values , but i am unable to understand what to pass for fill() arguments) please help me
Array.apply(null, {length: N}).map(Number.call, Number)

Eloquent Javascript: Exercise: A list

I am learning JavaScript from a book called 'Eloquent Javascript'
I'm trying to solve the exercise described here: http://eloquentjavascript.net/04_data.html#h_nSTX34CM1M
I managed to work out that this code works:
function arrayToList(array) {
var list = null;
for (var i = array.length - 1; i >= 0; i--)
list = {
value: array[i],
rest: list
};
return list;
}
console.log(arrayToList([1, 2, 3]));
Result: { value: 1, rest: { value: 2, rest: { value: 3, rest: null } } }
So far, so good, and according to the book this is the right solution. BUT!
When I try to run the same thing but instead with a longer array, let's say:
console.log(arrayToList([1, 2, 3, 4, 5]));
The result is: { value: 1, rest: { value: 2, rest: { value: 3, rest: [Object] } } }
Why is this? Is my code wrong?
There's nothing wrong with a longer array. console.log() is a non-standard, browser-specific implementation and some implementations set a cap on how many levels of object nesting they will display. When they hit that level, they just display [Object] rather than recurse into it to show deeper nesting.
If you actually set a breakpoint and examine your variable in the debugger, you will see you can expand the nested levels as deep as it goes and see everything.
Or, you could do this:
console.log(JSON.stringify(arrayToList([1, 2, 3, 4, 5])));
to manually convert the whole thing to a string before using console.log() on it.

Categories