I'm trying to reverse the contents of an array. My approach works well when the contents of the said array are of same type. but once they're of different types it just doesn't work. Constraint is that i can't use the .reverse() method and if possible, without creating a new array.
The answer in this question is close to what i want but i don't understand it.
Here is my code...
reverse.js
#!/usr/bin/node
exports.rev = function (list) {
for (let i = 0, j = (list.length - 1); i <= (list.length / 2); i++, j--) {
[list[i], list[j]] = [list[j], list[i]];
}
return (list);
};
main.js
#!/usr/bin/node
const rev = require('./reverse').rev;
console.log(rev([1, 2, 3, 4, 5]));
console.log(rev(["School", 89, { id: 12 }, "String"]));
Expected:
[5, 4, 3, 2, 1]
["String", { id: 12 }, 89, "School"]
What I got:
[5, 4, 3, 2, 1]
["String", 89, { id: 12 }, "School"]
I've found out that your code almost works. You just need to modify the condition a bit to
i < (list.length / 2) //not `<=`
function rev(list) {
for (let i = 0, j = (list.length - 1); i < (list.length / 2); i++, j--) {
[list[i], list[j]] = [list[j], list[i]];
}
return (list);
};
console.log(rev([1, 2, 3, 4, 5]));
console.log(rev(["School", 89, { id: 12 }, "String"]));
let array = [1, 2, 3, 4, 5]
let reverse = [];
for (var i = array.length - 1; i >= 0; i--){
reverse.push(array[i]);
}
You can try with a for loop like this:
let arr = ["School", 89, { id: 12 }, "String"];
let newArr = [];
for (let i = arr.length - 1; i >= 0; i--) {
newArr.push(arr[i])
}
console.log(newArr);
Expected output: ["String", [object Object] { id: 12 }, 89, "School"]
You can user a recursion to reverse
You can use Spread operator(...) along with distructure assignment for that.
function rev(arr) {
const [first, ...rest] = arr
return arr.length > 1 ? [...rev(rest), first] : arr
}
console.log(rev([1, 2, 3, 4, 5]));
console.log(rev(["School", 89, { id: 12 }, "String"]));
const [first, ...rest] = arr is a shortcut for:
const first = arr[0]
const rest = arr.slice(1)
However, ...rev(rest) will spread items of returned array and spread them. So, [...rev(rest), first] will keep the output of rev first and then push first at the end of array.
If you are comfortable with mutation of original array, try this
function rev(arr) {
return arr.length > 1 ? [arr.pop(), ...rev(arr)] : arr
}
console.log(rev([1, 2, 3, 4, 5]));
console.log(rev(["School", 89, { id: 12 }, "String"]));
Already good answers (and examples of arrays) here
My try with native methods:
const rev = (arr) => {
len = arr.length;
for (i = 1; i<= len; i++) arr.splice(len-i,0,arr.shift());
}
const array = ["School", 89, { id: 12 }, "String"];
console.log("original",array);
rev(array);
console.log("reversed",array);
Related
I have a problem needing two arrays containing some similar values and different values. I need to concat the arrays into a new array and remove the similar values only showing the individual values. something like arr1 = [1, 44, 2, 3, 5], arr2 = [33, 1, 2, 3, 4, 5], arr3 = [], return arr3 [44, 33, 4]. I have tried a few different ways with no success, one using a nested for loop and the other using .filter(). Any thoughts on how I can solve this? Here is my code:
const arrayDiffs = (arr1, arr2) => {
let arr3 = [];
for (let i = 0; i < arr1.length; i++) {
if (arr3.indexOf(arr1[i]) === -1) {
arr3.push(arr1[1]);
}
for (let n = 0; n < arr2.length; n++) {
if (arr3.indexOf(arr2[n]) === -1) {
arr3.push(arr2[n]);
}
}
return arr3;
};
}
console.log(arrayDiffs([1, 44, 2, 3, 5], [33, 1, 2, 3, 4, 5]));
I have also tried this way:
let arr3 = [];
const arrayDiffs = (arr1, arr2) => {
arr3 = arr1.concat(arr2);
arr3 = arr3.filter(function(item, index) {
if(arr3.indexOf(item) == index){
return true;
}
return false;
});
}
console.log(arrayDiffs([1, 44, 2, 3, 5], [33, 1, 2, 3, 4, 5]));
const myFunc = (a,b) => {
const a_but_not_b = a.filter(x=>!b.includes(x));
const b_but_not_a = b.filter(x=>!a.includes(x));
return [...a_but_not_b,...b_but_not_a];
}
console.log(myFunc([1,2,3],[2,3,4]));
But, let me explain more:
Use filter and includes to get difference.
Last I concat the arrays using spread operator [...a,...b].
Using your first method only we can achieve this. You have to do the following modifications.
for (let i = 0; i < arr1.length; i++) {
if (arr2.indexOf(arr1[i]) === -1) { // first compare the value with arr2 and arr1 and push the non-available values into arr3
arr3.push(arr1[i]);
}
}
for (let n = 0; n < arr2.length; n++) {
if (arr1.indexOf(arr2[n]) === -1) { //compare the value with arr1 and arr2 and push the non-available values into arr3
arr3.push(arr2[n]);
}
}
const arrayDiffs = (arr1, arr2) => {
let arr3 = [];
for (let i = 0; i < arr1.length; i++) {
if (arr2.indexOf(arr1[i]) === -1) {
arr3.push(arr1[i]);
}
}
for (let n = 0; n < arr2.length; n++) {
if (arr1.indexOf(arr2[n]) === -1) {
arr3.push(arr2[n]);
}
}
return arr3;
}
console.log(arrayDiffs([1, 44, 2, 3, 5], [33, 1, 2, 3, 4, 5]));
Have you tried sets in javassript. I think they are used for storing only unique elements.this will bring down you complexity to O(N), where N is total number of elements in arrays. Example :
const letters = new Set()
[...arr1,...arr2].filter(e=>!(arr1.includes(e)&&arr2.includes(e)))
var arr1 = [1, 44, 2, 3, 5],
arr2 = [33, 1, 2, 3, 4, 5],
arr3 = [...arr1,...arr2]
.filter(e=>!(arr1.includes(e)&&arr2.includes(e)));
console.log(arr3);
How to find the difference between the min and max indexes of the same value in an array with one loop with complexity exactly O(N)?
For example, given array A:
[4, 6, 2, 2, 6, 6, 1];
the function returns 4.
I'd use reduce to remember the first index of each value, then update the last value and maximum spread as I went along, e.g.
var data = [4, 6, 2, 2, 6, 6, 1];
function getMaxIndexSpread(data) {
return data.reduce(function(acc, value, index) {
if (value in acc) {
acc[value].lastIndex = index
} else {
acc[value] = {firstIndex: index, lastIndex: index};
}
var spread = acc[value].lastIndex - acc[value].firstIndex;
if (acc.maxSpread < spread) acc.maxSpread = spread;
return acc;
}, {maxSpread: 0}).maxSpread;
}
console.log(getMaxIndexSpread(data));
There's likely a funkier way, but this makes sense to me.
var data = [4, 6, 2, 2, 6, 6, 1];
console.log(Math.max(...data.map((v,i) => i - data.indexOf(v))));
var arr = [4, 6, 2, 2, 6, 6, 1];
function test(arr) {
var resultArr = [];
arr.map(function (v, i, a) {
for (var j = arr.length - 1; j >= 0; j--) {
if (v == arr[j]) {
resultArr.push({value: v, result: j - i});
// console.log(v+'的折扣值'+(j-i));
break;
}
}
})
resultArr.sort(function (a, b) {
return b.result - a.result;
})
console.log(resultArr[0])
}
test(arr);
Try with Array#filter .filter the array without max and min value .Then find max value in filtered array .... its spread syntax
var data = [4, 6, 2, 2, 6, 6, 1];
function bet(data) {
return Math.max(...data.filter(a => a != Math.max(...data) && a != Math.min(...data)))
}
console.log(bet(data))
Question has been moved to CodeReview: https://codereview.stackexchange.com/questions/154804/find-a-list-of-objects-in-an-array-with-javascript
Having an array of objects - such as numbers - what would be the most optimal (Memory and CPU efficiency) way if finding a sub group of objects? As an example:
demoArray = [1,2,3,4,5,6,7]
Finding [3,4,5] would return 2, while looking for 60 would return -1.
The function must allow for wrapping, so finding [6,7,1,2] would return 5
I have a current working solution, but I'd like to know if it could be optimized in any way.
var arr = [
1,
5,2,6,8,2,
3,4,3,10,9,
1,5,7,10,3,
5,6,2,3,8,
9,1]
var idx = -1
var group = []
var groupSize = 0
function findIndexOfGroup(g){
group = g
groupSize = g.length
var beginIndex = -2
while(beginIndex === -2){
beginIndex = get()
}
return beginIndex
}
function get(){
idx = arr.indexOf(group[0], idx+1);
if(idx === -1 || groupSize === 1){
return idx;
}
var prevIdx = idx
for(var i = 1; i < groupSize; i++){
idx++
if(arr[getIdx(idx)] !== group[i]){
idx = prevIdx
break
}
if(i === groupSize - 1){
return idx - groupSize + 1
}
}
return -2
}
function getIdx(idx){
if(idx >= arr.length){
return idx - arr.length
}
return idx
}
console.log(findIndexOfGroup([4,3,10])) // Normal
console.log(findIndexOfGroup([9,1,1,5])) // Wrapping
You could use the reminder operator % for keeping the index in the range of the array with a check for each element of the search array with Array#every.
function find(search, array) {
var index = array.indexOf(search[0]);
while (index !== -1) {
if (search.every(function (a, i) { return a === array[(index + i) % array.length]; })) {
return index;
}
index = array.indexOf(search[0], index + 1);
}
return -1;
}
console.log(find([3, 4, 5], [1, 2, 3, 4, 5, 6, 7])); // 2
console.log(find([6, 7, 1, 2], [1, 2, 3, 4, 5, 6, 7])); // 5
console.log(find([60], [1, 2, 3, 4, 5, 6, 7])); // -1
console.log(find([3, 4, 5], [1, 2, 3, 4, 6, 7, 3, 4, 5, 9])); // 6
.as-console-wrapper { max-height: 100% !important; top: 0; }
My take on the problem is to use slice() and compare each subarray of length equal to the group's length to the actual group array. Might take a bit long, but the code is short enough:
// The array to run the tests on
var arr = [
1,
5, 2, 6, 8, 2,
3, 4, 3, 10, 9,
1, 5, 7, 10, 3,
5, 6, 2, 3, 8,
9, 1
];
// Check arrays for equality, provided that both arrays are of the same length
function arraysEqual(array1, array2) {
for (var i = array1.length; i--;) {
if (array1[i] !== array2[i])
return false;
}
return true;
}
// Returns the first index of a subarray matching the given group of objects
function findIndexOfGroup(array, group) {
// Get the length of both arrays
var arrayLength = array.length;
var groupLength = group.length;
// Extend array to check for wrapping
array = array.concat(array);
var i = 0;
// Loop, slice, test, return if found
while (i < arrayLength) {
if (arraysEqual(array.slice(i, i + groupLength), group))
return i;
i++;
}
// No index found
return -1;
}
// Tests
console.log(findIndexOfGroup(arr,[4,3,10])); // Normal
console.log(findIndexOfGroup(arr,[9,1,1,5])); // Wrapping
console.log(findIndexOfGroup(arr,[9,2,1,5])); // Not found
If the group is longer than the array, some errors might occur, but I leave it up to you to extend the method to deal with such situations.
I need to delete occurrences of an element if it occurs more than n times.
For example, there is this array:
[20,37,20,21]
And the output should be:
[20,37,21]
I thought one way of solving this could be with the splice method
First I sort the array it order to make it like this:
[20,20,37,21]
Then I check if the current element is not equal to the next and split the array into chunks, so it should look like:
[20, 20],[37],[21]
Later I can edit the chunk longer than 1 and join it all again.
This is what the code looks like in my head but didn't work in real life
var array = [20, 37, 20, 21];
var chunk = [];
for(i = 0; i < array.length; i++) {
if(array[i] !== array[i + 1]) {
var index = array.indexOf(array[i]);
chunk.push = array.splice(0, index) // cut from zero to last duplicate element
} else
var index2 = a.indexOf(a[i]);
chunk.push(a.splice(0, index));
}
with this code the output is
[[], [20, 20]]
I think It's something in the 'else' but can't figure it out what to fix.
As the logic you want to achieve is to delete n occurrences of element in an array, your code could be as follow:
var array = [1, 1, 3, 3, 7, 2, 2, 2, 2];
var n = 2;
var removeMultipleOccurences = function(array, n) {
var filteredArray = [];
var counts = {};
for(var i = 0; i < array.length; i++) {
var x = array[i];
counts[x] = counts[x] ? counts[x] + 1 : 1;
if (counts[x] <= n) filteredArray.push(array[i])
}
return filteredArray;
}
console.log(removeMultipleOccurences(array, n));
I came up with this one, based on array filter checking repeated values up to a limit, but I can see #Basim's function does the same.
function removeDuplicatesAbove(arr, max) {
if (max > arr.length) {max = arr.length;}
if (!max) {return arr;}
return arr.filter(function (v, i) {
var under = true, base = -1;
for (var n = 0; n < max; n++) {
base = arr.indexOf(v, base+1); if (base == -1) {break;}
}
if (base != -1 && base < i) {under = false;}
return under;
});
}
var exampleArray = [20, 37, 20, 20, 20, 37, 22, 37, 20, 21, 37];
console.log(removeDuplicatesAbove(exampleArray, 3)); // [20, 37, 20, 20, 37, 22, 37, 21]
Always when you use splice() you truncate the array. Truncate the array with the length of same values from the start with the help of lastIndexOf(). It always starts from 0.
[ 1, 1, 1, 2, 2, 2, 3, 4, 4, 5 ] // splice(0, 3)
[ 2, 2, 2, 3, 4, 4, 5 ] // splice(0, 3)
[ 3, 4, 4, 5 ] // splice(0, 1)
[ 4, 4, 5 ] // splice(0, 2)
[ 5 ] // splice(0, 1)
Do this as long as the array length is greater than 0.
var arr = [1, 1, 1, 2, 2, 2, 3, 4, 4, 5];
var res = [];
while (arr.length > 0) {
var n = arr[0];
var last = arr.lastIndexOf(n) + 1;
res.push(n);
arr.splice(0, last);
}
console.log(res);
You can use Array.prototype.reduce(), Array.prototype.filter() to check if n previous elements are the same as current element
let cull = (arr, n) => arr.reduce((res, curr) => [...res
, res.filter(v => v === curr).length === n
? !1 : curr].filter(Boolean), []);
let arrays = [[20,37,20,21], [1,1,3,3,7,2,2,2,2]];
let cullone = cull(arrays[0], 1);
let cullthree = cull(arrays[1], 3);
console.log(cullone // [20, 37, 21]
, cullthree // [1, 1, 3, 3, 7, 2, 2, 2]
);
Say I have one large array like
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]
and would like to split it into an array of n-tuples like
[[1,2], [3,4], [5,6], [7,8], [9,10], [11,12], [13,14] /*, ... */ ] // (for n=2)
Is there some easy way to achieve this? The special case n = 2 would be enough for me.
This should work:
for (var i=0; i<arr.length; i+=2) {
result.push([arr[i], arr[i+1]]);
}
Came up with this, it should work for any number of "pockets" or whatever you want to call them. It checks for undefined so it works with odd number of items:
Array.prototype.pockets = function(n) {
var result = [],
pocket = [],
i, j;
for (i=0; i<this.length; i+=n) {
pocket.length = 0;
for (j=1; j<n; j++) if (this[i+j] != null) pocket.push(this[i+j]);
result.push([this[i]].concat(pocket));
}
if (arguments.length > 1) {
return result.pockets.apply(result, [].slice.call(arguments,1));
}
return result;
};
// Usage:
var arr = [1,2,3,4,5,6,7,8,9,10,11];
arr.pockets(2); //=> [[1,2],[3,4],[5,6],[7,8],[9,10],[11]]
arr.pockets(3); //=> [[1,2,3],[4,5,6],[7,8,9],[10,11]]
// Recursive:
arr.pockets(1,3); //=> [ [[1],[2],[3]], [[4],[5],[6]], [[7],[8],[9]], [[10],[11]] ]
This can be done much simpler by using Array.slice:
function grouper(lst, size) {
var result = [], i=0, n=lst.length;
while(i < n) {
result.push(lst.slice(i, i+size));
i += size;
}
return result
}
It's also much more efficient: http://jsperf.com/grouper
For an underscore variant, you can achieve this with _.groupBy(), grouping by the index of the item:
var doubles = _.groupBy(singles, function (num, i) {
return Math.floor(i / 2);
});
Though, since _.groupBy() returns an Object, getting an Array takes some additional work:
_.mixin({
segment: function (coll, per) {
var result = [];
_.chain(coll)
.groupBy(function (item, i) { return Math.floor(i / per)})
.each(function (group, key) { result[key] = group; })
return result;
}
});
var singles = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18];
var doubles = _.segment(singles, 2);
var triples = _.segment(singles, 3);
In python this can be done with zip(*[iter(xs)]*n). Just for fun, here's a JS implementation:
Let's start with a poor man's generator (that's all we've got until ES6 spreads around):
StopIteration = {"name": "StopIteration"}
function iter(xs) {
if('next' in xs)
return xs;
var i = 0;
return {
next: function() {
if(i >= xs.length)
throw StopIteration;
return xs[i++];
}
}
}
next = function(it) { return it.next() }
zip() is trivial:
zip = function() {
var args = [].map.call(arguments, iter), chunks = [];
while(1) {
try {
chunks.push(args.map(next));
} catch(StopIteration) {
return chunks;
}
}
}
Now, to create chained pairs just pass the same iter twice to zip:
xs = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
it = iter(xs)
a = zip(it, it)
console.log(a)
// [[1,2],[3,4],[5,6],[7,8],[9,10],[11,12]]
For N-pairs an additional utility is required:
repeat = function(x, n) {
for(var a = []; n; n--)
a.push(x);
return a;
}
a = zip.apply(this, repeat(iter(xs), 5))
console.log(a)
// [[1,2,3,4,5],[6,7,8,9,10]]
Note that like in Python this strips incomplete chunks.