Zip arrays with different size using lodash - javascript

Is there a way in lodash to zip two arrays of different size, where the result would like this
_.zip(['a', 'b', 'c'], [1,2]) -> [['a', 1], ['b', 2], ['c', 1]]
So it should start just from the beginning if one array reach its end

You can create a new array, in which the 2nd array will be repeated, and then _zip() it with the original array.
The example assumes that the 2nd array is the shorter one.
function repeatingZip(arr1, arr2) {
var ratio = Math.ceil(arr1.length / arr2.length); // how many times arr2 fits in arr1
var pattern = _(new Array(ratio)) // create a new array with the length of the ratio
.fill(arr2) // fill each item with the 2nd array
.flatten() // flatten it to an array
.take(arr1.length) // remove redundant items
.value();
return _.zip(arr1, pattern);
}
var result = repeatingZip(['a', 'b', 'c', 'd', 'e'], [1,2]);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

You can use the _.zipWith function that allows you to modify the result of zip.
You can then sort out the size problem in a number of ways. In this one, I calculate the size difference and use it to provide a value when the function callback gets an undefined value (this happens when the size of one of the arrays is exceeded).
var idxWrp = function(arr1, arr2) {
var index = 0,
diff = Math.abs(_.size(arr1) - _.size(arr2)) - 1;
return function(a, b) {
a = _.isUndefined(a) ? arr1[index % diff] : a;
b = _.isUndefined(b) ? arr2[index % diff] : b;
index++;
return [a, b];
};
},
arr1 = [1, 2, 3],
arr2 = [1, 2, 3, 4, 5, 6, 7],
res = _.zipWith(arr1, arr2, idxWrp(arr1, arr2));
console.log(res);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

Related

Concatinate different type arrays

suppose, array1 = ['B', 'G', 'R', 'A'], array2 is Uint8Array, how to concatinate these two arrays ?
I used var array3 = array1.concat(array2), but the result seems wrong , and array3.length is alwalys 5, regardless of content of array2.
You can do:
var array2 = Array.from(uint8Array);
var array3 = array1.concat(array2);
Your result (array3) must also be a Uint8Array array.
So, in your example the following should achieve what you're looking for:
const array3 = new Uint8Array([ ...array1, ...array2]);
Your code is creating a new array with your four strings followed by the Uint8Array as a single element.
Array.prototype.concat is an odd beast. If you give it arguments that aren't "concat spreadable" (for instance, things that aren't arrays), it includes those values as simple elements in the array it creates.
Typed arrays are not concat spreadable:
const uint8 = Uint8Array.from([3, 4]);
console.log(uint8[Symbol.isConcatSpreadable]); // undefined (and the default is false)
const softArray = [1, 2];
const result = softArray.concat(uint8);
console.log(result.length); // 3
console.log(result[0]); // 1
console.log(result[1]); // 2
console.log(result[2]); // (A Uint8Array containing 3, 4)
You could use spread instead of concat:
const array1 = ['B', 'G', 'R', 'A'];
const array2 = Uint8Array.from([1, 2, 3]);
const result = [...array1, ...array2];
console.log(result); // ["B", "g", "R", "a", 1, 2, 3]

React js Array and Array Reverse issue without mutating original array [duplicate]

Array.prototype.reverse reverses the contents of an array in place (with mutation)...
Is there a similarly simple strategy for reversing an array without altering the contents of the original array (without mutation)?
You can use slice() to make a copy then reverse() it
var newarray = array.slice().reverse();
var array = ['a', 'b', 'c', 'd', 'e'];
var newarray = array.slice().reverse();
console.log('a', array);
console.log('na', newarray);
In ES6:
const newArray = [...array].reverse()
Another ES6 variant:
We can also use .reduceRight() to create a reversed array without actually reversing it.
let A = ['a', 'b', 'c', 'd', 'e', 'f'];
let B = A.reduceRight((a, c) => (a.push(c), a), []);
console.log(B);
Useful Resources:
Array.prototype.reduceRight()
Arrow Functions
Comma Operator
const originalArray = ['a', 'b', 'c', 'd', 'e', 'f'];
const newArray = Array.from(originalArray).reverse();
console.log(newArray);
There are multiple ways of reversing an array without modifying. Two of them are
var array = [1,2,3,4,5,6,7,8,9,10];
// Using Splice
var reverseArray1 = array.splice().reverse(); // Fastest
// Using spread operator
var reverseArray2 = [...array].reverse();
// Using for loop
var reverseArray3 = [];
for(var i = array.length-1; i>=0; i--) {
reverseArray.push(array[i]);
}
Performance test http://jsben.ch/guftu
Try this recursive solution:
const reverse = ([head, ...tail]) =>
tail.length === 0
? [head] // Base case -- cannot reverse a single element.
: [...reverse(tail), head] // Recursive case
reverse([1]); // [1]
reverse([1,2,3]); // [3,2,1]
reverse('hello').join(''); // 'olleh' -- Strings too!
An ES6 alternative using .reduce() and spreading.
const foo = [1, 2, 3, 4];
const bar = foo.reduce((acc, b) => ([b, ...acc]), []);
Basically what it does is create a new array with the next element in foo, and spreading the accumulated array for each iteration after b.
[]
[1] => [1]
[2, ...[1]] => [2, 1]
[3, ...[2, 1]] => [3, 2, 1]
[4, ...[3, 2, 1]] => [4, 3, 2, 1]
Alternatively .reduceRight() as mentioned above here, but without the .push() mutation.
const baz = foo.reduceRight((acc, b) => ([...acc, b]), []);
const arrayCopy = Object.assign([], array).reverse()
This solution:
-Successfully copies the array
-Doesn't mutate the original array
-Looks like it's doing what it is doing
There's a new tc39 proposal, which adds a toReversed method to Array that returns a copy of the array and doesn't modify the original.
Example from the proposal:
const sequence = [1, 2, 3];
sequence.toReversed(); // => [3, 2, 1]
sequence; // => [1, 2, 3]
As it's currently in stage 3, it will likely be implemented in browser engines soon, but in the meantime a polyfill is available here or in core-js.
Reversing in place with variable swap just for demonstrative purposes (but you need a copy if you don't want to mutate)
const myArr = ["a", "b", "c", "d"];
const copy = [...myArr];
for (let i = 0; i < (copy.length - 1) / 2; i++) {
const lastIndex = copy.length - 1 - i;
[copy[i], copy[lastIndex]] = [copy[lastIndex], copy[i]]
}
Jumping into 2022, and here's the most efficient solution today (highest-performing, and no extra memory usage).
For any ArrayLike type, the fastest way to reverse is logically, by wrapping it into a reversed iterable:
function reverse<T>(input: ArrayLike<T>): Iterable<T> {
return {
[Symbol.iterator](): Iterator<T> {
let i = input.length;
return {
next(): IteratorResult<T> {
return i
? {value: input[--i], done: false}
: {value: undefined, done: true};
},
};
},
};
}
This way you can reverse-iterate through any Array, string or Buffer, without any extra copy or processing for the reversed data:
for(const a of reverse([1, 2, 3])) {
console.log(a); //=> 3 2 1
}
It is the fastest approach, because you do not copy the data, and do no processing at all, you just reverse it logically.
Is there a similarly simple strategy for reversing an array without altering the contents of the original array (without mutation) ?
Yes, there is a way to achieve this by using to[Operation] that return a new collection with the operation applied (This is currently at stage 3, will be available soon).
Implementation will be like :
const arr = [5, 4, 3, 2, 1];
const reversedArr = arr.toReverse();
console.log(arr); // [5, 4, 3, 2, 1]
console.log(reversedArr); // [1, 2, 3, 4, 5]
Not the best solution but it works
Array.prototype.myNonMutableReverse = function () {
const reversedArr = [];
for (let i = this.length - 1; i >= 0; i--) reversedArr.push(this[i]);
return reversedArr;
};
const a = [1, 2, 3, 4, 5, 6, 7, 8];
const b = a.myNonMutableReverse();
console.log("a",a);
console.log("////////")
console.log("b",b);
INTO plain Javascript:
function reverseArray(arr, num) {
var newArray = [];
for (let i = num; i <= arr.length - 1; i++) {
newArray.push(arr[i]);
}
return newArray;
}
es6:
const reverseArr = [1,2,3,4].sort(()=>1)

Sort an array in order [duplicate]

I have 2 arrays:
var a = [1, 2, 3]
var b = [a, b, c]
What I want to get as a result is:
[[1, a], [2, b], [3, c]]
It seems simple but I just can't figure out.
I want the result to be one array with each of the elements from the two arrays zipped together.
Use the map method:
var a = [1, 2, 3]
var b = ['a', 'b', 'c']
var c = a.map(function(e, i) {
return [e, b[i]];
});
console.log(c)
DEMO
Zip Arrays of same length:
Using Array.prototype.map()
const zip = (a, b) => a.map((k, i) => [k, b[i]]);
console.log(zip([1,2,3], ["a","b","c"]));
// [[1, "a"], [2, "b"], [3, "c"]]
Zip Arrays of different length:
Using Array.from()
const zip = (a, b) => Array.from(Array(Math.max(b.length, a.length)), (_, i) => [a[i], b[i]]);
console.log( zip([1,2,3], ["a","b","c","d"]) );
// [[1, "a"], [2, "b"], [3, "c"], [undefined, "d"]]
Using Array.prototype.fill() and Array.prototype.map()
const zip = (a, b) => Array(Math.max(b.length, a.length)).fill().map((_,i) => [a[i], b[i]]);
console.log(zip([1,2,3], ["a","b","c","d"]));
// [[1, "a"], [2, "b"], [3, "c"], [undefined, "d"]]
Zip Multiple (n) Arrays:
const zip = (...arr) => Array(Math.max(...arr.map(a => a.length))).fill().map((_,i) => arr.map(a => a[i]));
console.log(zip([1,2], [3,4], [5,6])); // [[1,3,5], [2,4,6]]
Zipping by leveraging generator functions
You can also use a generator function to zip().
const a = [1, 2, 3]
const b = ['a', 'b', 'c']
/**
* Zips any number of arrays. It will always zip() the largest array returning undefined for shorter arrays.
* #param {...Array<any>} arrays
*/
function* zip(...arrays){
const maxLength = arrays.reduce((max, curIterable) => curIterable.length > max ? curIterable.length: max, 0);
for (let i = 0; i < maxLength; i++) {
yield arrays.map(array => array[i]);
}
}
// put zipped result in an array
const result = [...zip(a, b)]
// or lazy generate the values
for (const [valA, valB] of zip(a, b)) {
console.log(`${valA}: ${valB}`);
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
The above works for any number of arrays and will zip() the longest array so undefined is returned as a value for shorter arrays.
Zipping of all Iterables
Here a function which can be used for all Iterables (e.g. Maps, Sets or your custom Iterable), not just arrays.
const a = [1, 2, 3];
const b = ["a", "b", "c"];
/**
* Zips any number of iterables. It will always zip() the largest Iterable returning undefined for shorter arrays.
* #param {...Iterable<any>} iterables
*/
function* zip(...iterables) {
// get the iterator of for each iterables
const iters = [...iterables].map((iterable) => iterable[Symbol.iterator]());
let next = iters.map((iter) => iter.next().value);
// as long as any of the iterables returns something, yield a value (zip longest)
while(anyOf(next)) {
yield next;
next = iters.map((iter) => iter.next().value);
}
function anyOf(arr){
return arr.some(v => v !== undefined);
}
}
// put zipped result in aa array
const result = [...zip(a, new Set(b))];
// or lazy generate the values
for (const [valA, valB] of zip(a, new Set(b))) {
console.log(`${valA}: ${valB}`);
}
Obviously it would also be possible to just use [...Iterable] to transform any Iterable to an array and then use the first function.
Using the reduce method:
const a = [1, 2, 3]
const b = ['a', 'b', 'c']
var c = a.reduce((acc, curr, ind) => {
acc.push([curr, b[ind]]);
return acc;
}, []);
console.log(c)
With forEach method:
const a = [1, 2, 3]
const b = ['a', 'b', 'c']
const c = [];
a.forEach((el, ind) => {
c.push([el, b[ind]])
});
console.log(c)
Providing a solution with imperative programming by a simple for loop.
This performs better when doing the zip operation on huge data sets compared to the convenient array functions like map() and forEach().
Example:
const a = [1, 2, 3];
const b = ['a', 'b', 'c'];
const result = [];
for (let i = 0; i < a.length; i++) {
result.push([a[i], b[i]]);
}
console.log(result);
And if you want a 1 line simpler solution then you can use a library like ramda which has a zip function.
Example:
const a = [1, 2, 3];
const b = ['a', 'b', 'c'];
const result = R.zip(a, b);
console.log(result);

Append To Multi-dimensional array where matching matching another array

I have two arrays:
a = [
[a, b],
[c, d],
[e, f],
[g, h]
]
b = [
[a, 4],
[1, 2],
[e, 3]
]
when a[i][0], matches b[i][0], I need to add a value to the current index of a. For this example, when a[0][1] matches b[0][1], a[0][1] should look like [a,b,new_value].
If this means creating a new array with all of the values of a, that is fine, but the original values and order of a cannot change.
I have tried numerous variations of for loops and reverse for loops. I am at a loss.
Thanks in advance.
Not too bad with a map + find. For each item of the a array, see if there is a matching element in the b array, and if so, add your new value:
const a = [
["a","b"],
["c","d"],
["e","f"],
["g","h"],
];
const b = [
["a",4],
[1,2],
["e",3],
];
const mapped = a.map(x => {
const match = b.find(y => y[0] === x[0]);
if (match) return [...x, "new value"] // Replace "new value" with whatever you want to add...
return x;
});
console.log(mapped)
Iterate the 1st array with Array#map. Compare each sub array's 1st item to a sub array in the 2nd array at the same index. If they match, concat a value to the sub array from the 1st array, and return it. If not, return the sub array.
Note: concat and map create new arrays, and don't change the original.
var a = [["a","b"],["c","d"],["e","f"],["g","h"]];
var b = [["a",4],[1,2],["e",3]];
var result = a.map(function(item, i) {
return b[i] && item[0] === b[i][0] ? item.concat(b[i][1]) : item; // replace b[i][1] with whatever value you want to add
});
console.log(result);
You could map the result of the check by using a default value, if the length of the given arrays are different.
var array1 = [['a', 'b'], ['c', 'd'], ['e', 'f'], ['g', 'h']],
array2 = [['a', 4], [1, 2], ['e', 3]],
result = array1.map((a, i) => a.concat(a[0] === (array2[i] || [])[0] ? array2[i][1] : []));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Reverse array in Javascript without mutating original array

Array.prototype.reverse reverses the contents of an array in place (with mutation)...
Is there a similarly simple strategy for reversing an array without altering the contents of the original array (without mutation)?
You can use slice() to make a copy then reverse() it
var newarray = array.slice().reverse();
var array = ['a', 'b', 'c', 'd', 'e'];
var newarray = array.slice().reverse();
console.log('a', array);
console.log('na', newarray);
In ES6:
const newArray = [...array].reverse()
Another ES6 variant:
We can also use .reduceRight() to create a reversed array without actually reversing it.
let A = ['a', 'b', 'c', 'd', 'e', 'f'];
let B = A.reduceRight((a, c) => (a.push(c), a), []);
console.log(B);
Useful Resources:
Array.prototype.reduceRight()
Arrow Functions
Comma Operator
const originalArray = ['a', 'b', 'c', 'd', 'e', 'f'];
const newArray = Array.from(originalArray).reverse();
console.log(newArray);
There are multiple ways of reversing an array without modifying. Two of them are
var array = [1,2,3,4,5,6,7,8,9,10];
// Using Splice
var reverseArray1 = array.splice().reverse(); // Fastest
// Using spread operator
var reverseArray2 = [...array].reverse();
// Using for loop
var reverseArray3 = [];
for(var i = array.length-1; i>=0; i--) {
reverseArray.push(array[i]);
}
Performance test http://jsben.ch/guftu
Try this recursive solution:
const reverse = ([head, ...tail]) =>
tail.length === 0
? [head] // Base case -- cannot reverse a single element.
: [...reverse(tail), head] // Recursive case
reverse([1]); // [1]
reverse([1,2,3]); // [3,2,1]
reverse('hello').join(''); // 'olleh' -- Strings too!
An ES6 alternative using .reduce() and spreading.
const foo = [1, 2, 3, 4];
const bar = foo.reduce((acc, b) => ([b, ...acc]), []);
Basically what it does is create a new array with the next element in foo, and spreading the accumulated array for each iteration after b.
[]
[1] => [1]
[2, ...[1]] => [2, 1]
[3, ...[2, 1]] => [3, 2, 1]
[4, ...[3, 2, 1]] => [4, 3, 2, 1]
Alternatively .reduceRight() as mentioned above here, but without the .push() mutation.
const baz = foo.reduceRight((acc, b) => ([...acc, b]), []);
const arrayCopy = Object.assign([], array).reverse()
This solution:
-Successfully copies the array
-Doesn't mutate the original array
-Looks like it's doing what it is doing
There's a new tc39 proposal, which adds a toReversed method to Array that returns a copy of the array and doesn't modify the original.
Example from the proposal:
const sequence = [1, 2, 3];
sequence.toReversed(); // => [3, 2, 1]
sequence; // => [1, 2, 3]
As it's currently in stage 3, it will likely be implemented in browser engines soon, but in the meantime a polyfill is available here or in core-js.
Reversing in place with variable swap just for demonstrative purposes (but you need a copy if you don't want to mutate)
const myArr = ["a", "b", "c", "d"];
const copy = [...myArr];
for (let i = 0; i < (copy.length - 1) / 2; i++) {
const lastIndex = copy.length - 1 - i;
[copy[i], copy[lastIndex]] = [copy[lastIndex], copy[i]]
}
Jumping into 2022, and here's the most efficient solution today (highest-performing, and no extra memory usage).
For any ArrayLike type, the fastest way to reverse is logically, by wrapping it into a reversed iterable:
function reverse<T>(input: ArrayLike<T>): Iterable<T> {
return {
[Symbol.iterator](): Iterator<T> {
let i = input.length;
return {
next(): IteratorResult<T> {
return i
? {value: input[--i], done: false}
: {value: undefined, done: true};
},
};
},
};
}
This way you can reverse-iterate through any Array, string or Buffer, without any extra copy or processing for the reversed data:
for(const a of reverse([1, 2, 3])) {
console.log(a); //=> 3 2 1
}
It is the fastest approach, because you do not copy the data, and do no processing at all, you just reverse it logically.
Is there a similarly simple strategy for reversing an array without altering the contents of the original array (without mutation) ?
Yes, there is a way to achieve this by using to[Operation] that return a new collection with the operation applied (This is currently at stage 3, will be available soon).
Implementation will be like :
const arr = [5, 4, 3, 2, 1];
const reversedArr = arr.toReverse();
console.log(arr); // [5, 4, 3, 2, 1]
console.log(reversedArr); // [1, 2, 3, 4, 5]
Not the best solution but it works
Array.prototype.myNonMutableReverse = function () {
const reversedArr = [];
for (let i = this.length - 1; i >= 0; i--) reversedArr.push(this[i]);
return reversedArr;
};
const a = [1, 2, 3, 4, 5, 6, 7, 8];
const b = a.myNonMutableReverse();
console.log("a",a);
console.log("////////")
console.log("b",b);
INTO plain Javascript:
function reverseArray(arr, num) {
var newArray = [];
for (let i = num; i <= arr.length - 1; i++) {
newArray.push(arr[i]);
}
return newArray;
}
es6:
const reverseArr = [1,2,3,4].sort(()=>1)

Categories