What I'd like to do is compare 2 arrays of primitives using chai.js, but without considering the order of elements - like if they were 2 sets.
Now obviously I can do something like this:
const actual = ['a', 'b', 'c'];
const expected = ['b', 'c', 'a'];
expect(actual).to.have.length(expected.length);
expected.forEach(e => expect(actual).to.include(e));
But I'm curious if there is a prefered 'built in' way of doing this (I couldn't find it in the docs).
You can use the built in check 'members':
expect([4, 2]).to.have.members([2, 4])
Answers above expect([4, 2]).to.have.members([2, 4]) won't check the size as author mentioned about.
expect([1,2,2]).to.have.members([1,2]) will pass the test.
The best option is to use https://www.chaijs.com/plugins/deep-equal-in-any-order/
You can use the members assertion from chai BDD.
var mocha = require('mocha');
var should = require('chai').should();
let a = ['a', 'b', 'c'];
let b = ['c', 'a', 'b'];
let c = ['d', 'e', 'c', 'b'];
describe('test members', function() {
it('should pass', function() {
a.should.have.members(b);
});
it('should fail', function() {
a.should.not.have.members(c);
});
});
Related
Is it possible to filter an array with multiple values with liner time O(N) the current example should be O(n^{2}), is it possible to run it faster? (In real world app I will have thousands of elements).
Could you point me out in the right direction?
const data = ['a', 'b', 'c', 'd'];
const filterBy = ['c', 'a'];
const r = data.filter(x => filterBy.includes(x));
console.log(r);
yes it is possible.
you can use hash set which will provide you lookup of an element in O(1) (on average) instead of the filterBy array.
example:
const data = ['a', 'b', 'c', 'd'];
const filterBy = ['c', 'a'];
const filterBySet = new Set(filterBy)
const r = data.filter(x => filterBySet.has(x));
console.log(r);
I like to use Array.prototype.reduce() for several different scenarios in my code, it's pretty straightforward and handy.
Please observe in the 2 different solutions below the reduce() function takes 2 different initial values, in the first case is new Set() and the second is [].
In the below example the code uses reduce() without return keyword - Set one:
const data = ['a', 'b', 'c', 'd', 'a', 'k', 'b'];
const result = data.reduce((a, c) => a.add(c), new Set());
console.log(Array.from(result));
The next example is using still reduce() but here with a return keyword - Array one:
const data = ['a', 'b', 'c', 'd', 'a', 'k', 'b'];
const result = data.reduce((a, c) => {
a.find(e => e === c) ? null : a.push(c);
return a;
}, []);
console.log(result);
Question:
So the .add() function for Set returns the Set object itself. The .push() function for Array returns the length of the used Array.
The Set case helps me to shorten the code using .reduce() without return keyword because the above mentioned reason. In my second example I would like to use the solution without return keyword but still with Array somehow.
Is there any workaround solution to get the same result but without using return keyword in the second example? I would like to shorten the code further if possible.
Any help is appreciated.
You could take either the accumulator, if found or concat the element to the accumulator.
const data = ['a', 'b', 'c', 'd', 'a', 'k', 'b'];
const result = data.reduce((a, c) => a.find(e => e === c) ? a : a.concat(c), []);
console.log(result);
Just to mention, Set takes a complete array with the constructor.
const data = ['a', 'b', 'c', 'd', 'a', 'k', 'b'];
const result = Array.from(new Set(data));
console.log(result);
Array#concat can add a new item to an array and returns a new array, so can works similar to Set#add. However, it still needs the conditional operator since you want to either add an element or nothing - for the latter case that's concatenating an array with an empty array:
const data = ['a', 'b', 'c', 'd', 'a', 'k', 'b'];
const result = data.reduce((a, c) => a.concat(a.some(e => e === c) ? [] : c), []);
console.log(result);
Alternatively, you can use spread syntax to again combine two arrays:
const data = ['a', 'b', 'c', 'd', 'a', 'k', 'b'];
const result = data.reduce((a, c) => [...a, ...(a.some(e => e === c) ? [] : c)], []);
console.log(result);
Neither of the two is perfect, to be honest. The existence of the conditional operator makes this harder to read when all one line but it's still an option.
I want to remove elements from an array when they match a certain regular expression.
Here is the Lodash documentation on the pull() method.
I want a result similar to this.
const array = ['a', 'b', 'c', 'a', 'b', 'c'];
_.pull(array, 'b', 'c',);
console.log(array); // [ 'a', 'a', ]
Only, I want to use regex instead of strings. But this does not achieve that result.
const array = ['a', 'b', 'c', 'a', 'b', 'c'];
const re = /(b|c)/gm
_.pull(array, re,);
console.log(array); // ["a", "b", "c", "a", "b", "c"]
What am I doing wrong?
The _.pull() method doesn't accept a predicate, use _.remove():
Removes all elements from array that predicate returns truthy for
const array = ['a', 'b', 'c', 'a', 'b', 'c'];
const re = /b|c/
_.remove(array, c => re.test(c));
console.log(array); // ["a", "a"]
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
If you're interested in a vanilla JS solution, see below for using RegExp test!
let array = ['a', 'b', 'c', 'a', 'b', 'c'];
const re = /(b|c)/
array = array.filter(el => !re.test(el));
console.log(array);
I have two arrays:
var one = ['A', 'B', 'C'];
var two = ['a', 'b', 'c'];
I want to merge them and get this:
var three = ['Aa', 'Bb', 'Cc'];
I looked for answers but I only found concat(), which gives
['A', 'B', 'C', 'a', 'b', 'c']
That is not what I want.
How can I merge the two arrays?
You can do a simple map function:
var three=one.map((item,index)=>item+two[index])
Just need to assume they all have same indices.
I want to get the remainder of an iterable like an array. Like so:
var arr = ['a', 'b', 'c'];
var brr = arr.slice(1);
But is there a terser way (maybe using destructuring assignment?).
Yes there is:
var [,...brr] = arr; // ['b', 'c']
Multiple elision also works:
var [,,...brr] = arr; // ['c']