Related
here is my code:
const reverseArr = (...args) => {
let length = args.length - 1
let reversed = []
let i = 0
for (let a = length - i; i <= length; i++) {
args[a] = reversed[i]
}
return reversed
}
console.log( reverseArr(3, 5, 4, 1) )
What's the problem here? Does it about value of 'i' or lenght?
function reverse(arr){
// get length
var len = arr.length;
// create new array
var newArr = [];
// loop through array
for(var i = len - 1; i >= 0; i--){
// push to new array
newArr.push(arr[i]);
}
// return new array
return newArr;}
reverse([1,2,3,4,5]);
try this.
There are multiple issues :
for initialisation happens once, so if you do let a = lemgth - i, it doesn't update a any further, even though i changes.
You're reassigning values to your input array itself with reversed array, which is empty itself.
You're output-ing the input array (arr).
I tried to fix your snippet, and also adding better approach:
const reverseArr = (...args) => {
let length = args.length - 1
let reversed = []
let i = 0
// update 'a' as soon as you update 'i'
for(let a = length - i; i <= length; i++, a = length - i){
// update the standby array 'reveresed'
reversed[i] = args[a]
}
// print the reversed array instead of 'args'
console.log(reversed)
}
// Alternate approach (in-place reverse)
const reverseInput = (...args) => {
let left = 0, right = args.length - 1;
while(left <= right) {
// swap the left and right elements in array
[args[left], args[right]] = [args[right], args[left]] ;
left++;
right--;
}
console.log(args);
}
// Approach 1
console.log(reverseArr(3, 5, 4, 1))
// Approach 2
console.log(reverseInput(3,5,4,1));
simply...
const reverseArr = (...args) => Array.from({length:args.length},_=>args.pop())
console.log( reverseArr(3, 5, 4, 1) )
if you want to use an array as argument and let it untouched:
const reverseArr = arr => Array.from({length:arr.length},(_,i)=>arr[(arr.length-++i)])
let arrOrigin = [3,5,4,1]
let arrResult = reverseArr( arrOrigin )
console.log( arrOrigin )
console.log( arrResult )
.as-console-wrapper {max-height: 100%!important;top:0 }
const numbers = [1, 2, 3, 4, 5];
const reverse = (array) => {
const reversed = [];
for (const [index, element] of numbers.entries())
reversed[array.length - index - 1] = element;
return reversed;
}
console.log(reverse(numbers)); // [ 5, 4, 3, 2, 1 ]
We can use a for ... of loop on the entries of the array we want to reverse, and push the element into the desired position of the array.
To calculate the position we want, we can just do array length - index - 1.
This means that if we have an array of 5 items, [1, 2, 3, 4, 5] and we iterate through, we will be doing...
5 - 0 - 1 = 4 for the index of the first item.
5 - 1 - 1 = 3 for the index of the second item.
5 - 2 - 1 = 2 for the index of the third item.
5 - 3 - 1 = 1 for the index of the fourth item.
5 - 4 - 1 = 0 for the index of the fifth item.
In javascript you can reverse an array with sort function
function reverseArr(a){
return a.sort((a,b)=>b-a)
}
Try this:
function reversearr(...args) {
let reversed = args
args.forEach((x, y) => {reversed[-(y+1)]=x})
}
I want to know how can I add 3 different number to the 3n, 3n+1 and 3n+2 indices. I mean for example I have following array :
var arr = [1,1,1,2,2,2,3,3,3]
and then I want add the (3n)th to 5 and then I want add (3n+1)th of an array to 2 and (3n+2) to 3,
I mean the final array I want to be like following result array:
var result = [6,3,4,7,4,5,8,5,6]
and I try to do it as following code:
// arr = [1,1,1,2,2,2,3,3,3]
let res = [];
for (let i = 0; i < arr.length; i++) {
res.push([arr[i*3] * 5,
arr[(i*3)+1] *2,
arr[(i*3)+2] *3])
}
This should do the trick:
var arr = [1,1,1,2,2,2,3,3,3],
add = [5,2,3], res=[];
// result = [6,3,4,7,4,5,8,5,6]
for (let i=0;i<arr.length;i+=add.length) add.forEach((v,j)=>res[i+j]=arr[i+j]+v);
console.log(JSON.stringify(res))
An alternative and even shorter solution (similar to #Robin's answer) would be:
var arr = [1,1,1,2,2,2,3,3,3],
add = [5,2,3], res=[];
res=arr.map((v,i)=>v+add[i%add.length]);
console.log(JSON.stringify(res))
( I noticed #Nina came up with a very similar answer ...)
You can simply use map, making use of the fact that its function argument takes the current index an optional second argument:
var arr = [1,1,1,2,2,2,3,3,3];
var result = arr.map((num, idx) => {
switch (idx % 3) {
case 0:
return num + 5;
case 1:
return num + 2;
case 2:
return num + 3;
}
});
console.log(result);
You could mapp the array directly by taking a closure over an index for the values array for adding.
var array = [1, 1, 1, 2, 2, 2, 3, 3, 3],
add = [5, 2, 3],
result = array.map((i => v => v + add[i++ % add.length])(0));
console.log(...result);
Is there a way to filter an array so that only the unique (distinct) items are left? (not to be confused with removing duplicated items)
I'm looking for something like this:
arrayDistinct([1, 2, 1, 3, 2, 4])
//=> [3, 4]
Here's a program that doesn't iterate through the input multiple times or create intermediate state (like counts) to arrive at the solution -
// distinct1.js
function distinct (values = [])
{ const r = new Set(values) // result
const s = new Set // seen
for (const v of values)
if (s.has(v))
r.delete(v)
else
s.add(v)
return Array.from(r)
}
console.log(distinct([ 1, 2, 3, 4, 1, 2, 5 ]))
// [ 3, 4, 5 ]
Technically, the Set constructor used above does iterate through the input to create the initial set. We can further optimise by starting with empty sets -
// distinct2.js
function distinct (values = [])
{ const r = new Set // result
const s = new Set // seen
for (const v of values)
if (s.has(v))
continue
else if (r.has(v))
(r.delete(v), s.add(v))
else
r.add(v)
return Array.from(r)
}
console.log(distinct([ 1, 2, 3, 4, 1, 2, 5 ]))
// [ 3, 4, 5 ]
To see the big effect small changes like this can make, let's consider a significantly large input. We will generate one million 7-digit numbers and find the distinct values using various approaches -
const rand = n =>
Math.floor(Math.random() * n)
const inrange = (min, max) =>
rand(max - min + 1) + min
const r =
Array.from(Array(1e6), _ => inrange(1e6, 1e7-1))
console.log(r)
[
5114931, 9106145, 8460777, 4453008, 2388497, 6013688, 2552937,
1804171, 1264251, 4848368, 9659369, 8420530, 7150842, 3490019,
9003395, 7645576, 8968872, 3617948, 6780357, 5715769, 7911037,
3293079, 6173966, 8016471, 3462426, 8048448, 5061586, 8478988,
1733908, 1007848, 7027309, 7210176, 8598863, 8341131, 4586641,
5121335, 7157381, 8835726, 5395867, 6145745, 5058377, 5817408,
6153398, 6514711, 9297841, 7851503, 1678386, 2833373, 9093901,
6002570, 4512648, 1586990, 9984143, 8618601, 5609095, 8971964,
9845723, 7884387, 8635795, 3105128, 2764544, 2213559, 5788547,
8729079, 2176326, 1339145, 8278925, 5598964, 5712291, 2302033,
3744467, 4555008, 3301943, 5993299, 6499550, 3125444, 5763790,
6476676, 7920890, 9299943, 5129401, 7414350, 6469143, 2246004,
6659545, 9269620, 8333459, 2468048, 6420650, 3330098, 7722297,
6082093, 8883388, 6240800, 8976961, 9192095, 4827011, 4202172,
9476644, 3786121,
... 999900 more items
]
Using a cursory benchmark program -
function benchmark (f, ...args)
{ console.time(f.name)
const r = f(...args)
console.timeEnd(f.name)
return r
}
We will measure the two solutions in this answer and compare them against another answer in this thread -
benchmark(distinct1, r) // first solution in this answer
benchmark(distinct2, r) // second solution in this answer
benchmark(distinct3, r) // solution from #hev1
Results -
distinct1: 406.695ms
distinct2: 238.350ms
distinct3: 899.650ms
The revised program runs about twice as fast as the first program, because it uses half the amount of iteration. Programs like #hev1's which use multiple iterations and/or allocate additional memory for each element result in a longer runtime.
Expand the program below to verify the results in your own browser -
// #user633183-1
function distinct1 (values = [])
{ const r = new Set(values)
const s = new Set
for (const v of values)
if (s.has(v))
r.delete(v)
else
s.add(v)
return Array.from(r)
}
// #user633183-2
function distinct2 (values = [])
{ const r = new Set
const s = new Set
for (const v of values)
if (s.has(v))
continue
else if (r.has(v))
(r.delete(v), s.add(v))
else
r.add(v)
return Array.from(r)
}
// #hev1
const distinct3 = arr => {
const freq = arr.reduce((acc,curr)=>(acc[curr]=(acc[curr]||0)+1,acc), {});
return arr.filter(x => freq[x] === 1);
}
function benchmark (f, ...args)
{ console.time(f.name)
const r = f(...args)
console.timeEnd(f.name)
return r
}
const rand = n =>
Math.floor(Math.random() * n)
const inrange = (min, max) =>
rand(max - min + 1) + min
const r =
Array.from(Array(1e6), _ => inrange(1e6, 1e7-1))
benchmark(distinct1, r) // 406.695ms
benchmark(distinct2, r) // 238.350ms
benchmark(distinct3, r) // 899.650ms
For enhanced performance, you can first iterate over the array once to create an object representing the frequency of each element and then filter the array to get all the elements with a frequency of 1. This solution runs in O(n) time and space.
const arrayDistinct = arr => {
const freq = arr.reduce((acc,curr)=>(acc[curr]=(acc[curr]||0)+1,acc), {});
return arr.filter(x => freq[x] === 1);
}
console.log(arrayDistinct([1, 2, 1, 3, 2, 4]));
For arrays that contain elements of different types that have the same string representation, we can use a Map instead of an object to store frequency.
const arrayDistinct = arr => {
const freq = arr.reduce((map,curr)=>(map.set(curr, (map.get(curr)||0)+1),map), new Map);
return arr.filter(x => freq.get(x) === 1);
}
console.log(arrayDistinct([1, 2, 1, 3, 2, 4, '1']));
const og = [1, 2, 1, 3, 2, 4];
const ogfrequency = {};
/*compute frequency of each elem*/
for (const i of og) {
ogfrequency[i] = ogfrequency[i] ? ++ogfrequency[i] : 1;
}
/*pass or fail the test of filter based on frequencies collected previously*/
const answer = og.filter((e) => ogfrequency[e] === 1);
console.info("answer::", answer);
This can be implemented like so:
const arrayDistinct = array => array.filter(value => array.indexOf(value) === array.lastIndexOf(value))
arrayDistinct([1, 2, 1, 3, 2, 4])
//=> [3, 4]
Something like
const values = [1, 2, 1, 3, 2, 4];
const results = values.filter(value =>
values.filter(v => v === value).length === 1
);
console.log(results);
I am trying to create an array alternating between 2 different values with a predetermined length.
Example:
conts value1 = 1;
const value2 = 2;
cont length = 6;
//desired output
const array1 = [1, 2, 1, 2, 1, 2];
You can create the array using Array.from with the desired length and map it to have the desired values :
const value1 = 1;
const value2 = 2;
const length = 6;
const result = Array.from({ length }).map((e, ndx) => ndx % 2 ? value2 : value1);
console.log(result);
Try with:
var repeated = new Array(3).fill([1, 2]).flat();
Or more general:
function repeat(n, value){
return new Array(n).fill(value).flat();
}
result = repeat(3, [1, 2]);
Credits: https://stackoverflow.com/a/54935305/4628597
An easy beginner solution would be something like this:
function createArray(value1, value2, length){
var array = new Array()
for(var i=0; i<length;i++){
if(i%2 == 0){
array.push(value1);
}else{
array.push(value2);
}
return array;
}
}
You could take an array of values in the wanted order and use a closure over the index of the values array adjusted by taking the remainder with the length of the values array.
const values = [1, 2],
length = 6,
result = Array.from({ length }, (i => _ => values[i++ % values.length])(0));
console.log(result);
I want to split an array into pairs of arrays.
var arr = [2, 3, 4, 5, 6, 4, 3, 5, 5]
would be
var newarr = [
[2, 3],
[4, 5],
[6, 4],
[3, 5],
[5]
]
You can use js reduce
initialArray.reduce(function(result, value, index, array) {
if (index % 2 === 0)
result.push(array.slice(index, index + 2));
return result;
}, []);
Lodash has a method for this: https://lodash.com/docs/4.17.10#chunk
_.chunk([2,3,4,5,6,4,3,5,5], 2);
// => [[2,3],[4,5],[6,4],[3,5],[5]]
There's no pre-baked function to do that, but here's a simple solution:
var splitPairs = function(arr) {
var pairs = [];
for (var i=0 ; i<arr.length ; i+=2) {
if (arr[i+1] !== undefined) {
pairs.push ([arr[i], arr[i+1]]);
} else {
pairs.push ([arr[i]]);
}
}
return pairs;
};
Yet another that's a bit of a mish-mash of the already-posted answers. Adding it because having read the answers I still felt things could be a little easier to read:
var groups = [];
for(var i = 0; i < arr.length; i += 2)
{
groups.push(arr.slice(i, i + 2));
}
There is now the flexible Array#flatMap(value, index, array):
const pairs = arr.flatMap((_, i, a) => i % 2 ? [] : [a.slice(i, i + 2)]);
And the possibly more efficient, but goofy looking Array.from(source, mapfn?):
const pairs = Array.from({ length: arr.length / 2 }, (_, i) => arr.slice(i * 2, i * 2 + 2))
It's possible to group an array into pairs/chunks in one line without libraries:
function chunks(arr, size = 2) {
return arr.map((x, i) => i % size == 0 && arr.slice(i, i + size)).filter(x => x)
}
console.log(chunks([1, 2, 3, 4, 5, 6, 7])) // -> [[1, 2], [3, 4], [5, 6], [7]]
Here's a good generic solution:
function splitInto(array, size, inplace) {
var output, i, group;
if (inplace) {
output = array;
for (i = 0; i < array.length; i++) {
group = array.splice(i, size);
output.splice(i, 0, group);
}
} else {
output = [];
for (i = 0; i < array.length; i += size) {
output.push(array.slice(i, size + i));
}
}
return output;
}
For your case, you can call it like this:
var arr= [2,3,4,5,6,4,3,5,5];
var newarr = splitInto(arr, 2);
The inplace argument determines whether the operation is done in-place or not.
Here's a demo below:
function splitInto(array, size, inplace) {
var output, i, group;
if (inplace) {
output = array;
for (i = 0; i < array.length; i++) {
group = array.splice(i, size);
output.splice(i, 0, group);
}
} else {
output = [];
for (i = 0; i < array.length; i += size) {
output.push(array.slice(i, size + i));
}
}
return output;
}
var arr= [2,3,4,5,6,4,3,5,5];
var newarr = splitInto(arr, 2);
disp(newarr);
// or we can do it in-place...
splitInto(arr, 3, true);
disp(arr);
function disp(array) {
var json = JSON.stringify(array);
var text = document.createTextNode(json);
var pre = document.createElement('pre');
pre.appendChild(text);
document.body.appendChild(pre);
}
A slightly different approach than using a for loop for comparison. To avoid modifying the original array slice makes a shallow copy since JS passes objects by reference.
function pairArray(a) {
var temp = a.slice();
var arr = [];
while (temp.length) {
arr.push(temp.splice(0,2));
}
return arr;
}
var array = [2,3,4,5,6,4,3,5,5];
var newArr = pairArray(array);
function pairArray(a) {
var temp = a.slice();
var arr = [];
while (temp.length) {
arr.push(temp.splice(0,2));
}
return arr;
}
document.write('<pre>' + JSON.stringify(newArr) + '</pre>');
I would use lodash for situations like this.
Here is a solution using _.reduce:
var newArr = _(arr).reduce(function(result, value, index) {
if (index % 2 === 0)
result.push(arr.slice(index, index + 2));
return result;
}, []);
var arr = [2,3,4,5,6,4,3,5,5];
var newArr = _(arr).reduce(function(result, value, index) {
if (index % 2 === 0)
result.push(arr.slice(index, index + 2));
return result;
}, []);
document.write(JSON.stringify(newArr)); // [[2,3],[4,5],[6,4],[3,5],[5]]
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.0/lodash.min.js"></script>
Here's another solution using lodash helpers:
function toPairs(array) {
const evens = array.filter((o, i) => i % 2);
const odds = array.filter((o, i) => !(i % 2));
return _.zipWith(evens, odds, (e, o) => e ? [o, e] : [o]);
}
console.log(toPairs([2,3,4,5,6,4,3,5,5]));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.13.1/lodash.min.js"></script>
const items = [1, 2, 3, 4, 5];
const createBucket = (bucketItems, bucketSize) => buckets => {
return bucketItems.length === 0 ? buckets : [...buckets, bucketItems.splice(0, bucketSize)];
};
const bucketWithItems = items.reduce(createBucket([...items], 4), []);
Here is a short and more generic solution:
function splitArrayIntoPairs(arr, n) {
var len = arr.length
var pairs = []
for (let i = 0; i < len; i += n) {
var temp = []
for (var j = i; j < (i + n); j++) {
if (arr[j] !== undefined) {
temp.push(arr[j])
}
}
pairs.push(temp)
}
return pairs
}
Where arr is your array and n is no of pairs
This combines some of the answers above but without Object.fromEntires. The output is similar to what you would get with minimist.
const splitParameters = (args) => {
const split = (arg) => (arg.includes("=") ? arg.split("=") : [arg]);
return args.reduce((params, arg) => [...params, ...split(arg)], []);
};
const createPairs = (args) =>
Array.from({ length: args.length / 2 }, (_, i) =>
args.slice(i * 2, i * 2 + 2)
);
const createParameters = (pairs) =>
pairs.reduce(
(flags, value) => ({
...flags,
...{ [value[0].replace("--", "")]: value[1] }
}),
{}
);
const getCliParameters = (args) => {
const pairs = createPairs(splitParameters(args));
const paramaters = createParameters(pairs);
console.log(paramaters);
return paramaters;
};
//const argsFromNodeCli = process.argv.slice(2); // For node
const testArgs = [
"--url",
"https://www.google.com",
"--phrases=hello,hi,bye,ok"
];
const output = getCliParameters(testArgs);
document.body.innerText = JSON.stringify(output);
Here is another concise but still efficient solution using modern JavaScript (arrow function, Array.prototype.at):
splitPairs = arr =>
arr.reduce((pairs, n, i) =>
(i % 2 ? pairs.at(-1).push(n)
: pairs.push([n]),
pairs), []);
It is (memory-)efficient because it just creates one array for the result and one array for each pair and then modifies them. The case where there is an odd number of elements is handled naturally.
When minified, it is also really concise code:
splitPairs = a=>a.reduce((p,n,i)=>(i%2?p.at(-1)[1]=n:p.push([n]),p),[]);
Using ES6 features:
const arr = [2, 3, 4, 5, 6, 4, 3, 5, 5]
const result = arr.slice(arr.length/2).map((_,i)=>arr.slice(i*=2,i+2))
console.log(result)
Here is another generic solution that uses a generator function.
/**
* Returns a `Generator` of all unique pairs of elements from the given `iterable`.
* #param iterable The collection of which to find all unique element pairs.
*/
function* pairs(iterable) {
const seenItems = new Set();
for (const currentItem of iterable) {
if (!seenItems.has(currentItem)) {
for (const seenItem of seenItems) {
yield [seenItem, currentItem];
}
seenItems.add(currentItem);
}
}
}
const numbers = [1, 2, 3, 2];
const pairsOfNumbers = pairs(numbers);
console.log(Array.from(pairsOfNumbers));
// [[1,2],[1,3],[2,3]]
What I like about this approach is that it will not consume the next item from the input until it actually needs it. This is especially handy if you feed it a generator as input, since it will respect its lazy execution.