'codewars Array.diff javascript
this is my first question as I'm learning programming for few days but now and I'm stuck
Task:
Your goal in this kata is to implement a difference function, which subtracts one list from another and returns the result.
It should remove all values from list
a, which are present in listbkeeping their order.
arrayDiff([1,2],[1]) == [2]
If a value is present inb, all of its occurrences must be removed from the other:
arrayDiff([1,2,2,2,3],[2]) == [1,3]
My solution:
function arrayDiff(a, b) {
for (var j = 0; j < a.length; j++) {
for (var i = 0; i < b.length; i++) {
if(a[j] == b[i]) {
a.splice(j);
j--;
}
}
}
return a;
}
Looks like I'm doing something wrong and peculiar thing happens: sometimes tests turn all red, sometimes all BUT 1 test turn red, while rest is green. The one that always fails me is:
Should pass Basic tests
a was [1,2], b was [1]: expected [] to deeply equal [ 2 ]
Solution 1:[1]
The problem with your function is, that you change the length of your a array while in a for loop, which uses the length of a. This causes certain index to be skipped.
function arrayDiff(a, b) {
for (var j = 0; j < a.length; j++) {
for (var i = 0; i < b.length; i++) {
if(a[j] == b[i]) {
// here you change the size of a.
a.splice(j);
j--;
}
}
}
return a;
}
To fix this, create a temporary array, in which you push all values from a, which are not contained in b.
function arrayDiff(a,b) {
// Temporary array, containing all values from a, which are not contained in b
let diffArray = [];
// Looping over a
for(let i = 0; i < a.length; i++) {
// Per default we say that b does not contain a
let bContainsAValue = false;
// Loop over b
for(let y = 0; y < b.length; y++) {
// If any value in b is the same as the current value from a, we set bContainsAValue to true
if(a[i] === b[y]) bContainsAValue = true;
}
// Now only if bContainsAValue is still false, meaning it does not contain the a value, we push this value into our temporary array
if(!bContainsAValue) diffArray.push(a[i]);
}
// In the end we return the temporary array
return diffArray;
}
Here is my approach, which is simpler and uses some array functions:
function arrayDiff(a, b) {
// Filter entire a array, only keep the value if b does not contain that value
return a.filter(val => !b.includes(val));
}
Solution 2:[2]
Here is an easy approach that you can take to solve the error in your code with a mix of ES6.
Since your array length changes over the loop, you can use delete array[j] to remove the value without changing the length of the array or the index of elements. According to this answer
If you just want to make the element at index
ino longer exist, but you don't want the indexes of the other elements to change:
This replaces the duplicate values with undefined. Then you can remove all the undefined elements with a single line
a.filter(Boolean)
function arrayDiff(a, b) {
for (var j = 0; j < a.length; j++) {
for (var i = 0; i < b.length; i++) {
if (a[j] == b[i]) {
delete a[j];
}
}
}
console.log(a.filter(Boolean))
return a.filter(Boolean);
}
arrayDiff([1, 2], [1])
arrayDiff([1, 2, 2, 2, 3], [2])
Here's a single liner using ES6 without any nesting or mutation
const arrayDiff = (a, b) => a.filter(item => !b.includes(item))
console.log(arrayDiff([1, 2], [1]))
console.log(arrayDiff([1, 2, 2, 2, 3], [2]))
Solution 3:[3]
You could use the builtin methods for array, and combine that with the set. Something like the following:
function diff(a, b) {
const left = a.filter(item => !b.includes(item))
const right = b.filter(item => !a.includes(item))
return Array.from(new Set([].concat(left, right)))
}
By your example
diff([1,2,2,2,3],[2]) // returns [1, 3]
diff([1,2],[1]) // returns [2]
The function should also be transitive, I.e the parameter order should not matter when calculating a difference. So flipping the parameters should return the same result.
diff([2], [1,2,2,2,3]) // returns [1, 3]
diff([1],[1,2]) // returns [2]
Solution 4:[4]
This also works:
# create a function, pass in the listNames as parameters
def array_diff(a, b):
# create an entity removeNum: the loop through b, to check if it's in list b
for removeNumber in b:
# If removeNum is in b, loop through a as well to check if it's there
while removeNumber in a:
# So, if removeNum is in list a
try:
# Try function to remove it from a... using .remove()
a.remove(removeNumber)
# except to return empty list
except ValueError:
return[]
return a
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | |
| Solution 3 | |
| Solution 4 | Atieno Obwanda |
