I have two one-dimensional arrays, a and b. a has values and b is empty. The length of a is an even number. I'd like to remove every other value from a and move them to b, in the same order as they were placed in a.
var a = [1, 2, 3, 4, 5, 6], b = [];
becomes
var a = [1, 3, 5], b = [2, 4, 6];
I figured that filter would do the trick but I'm not that happy with the performance of it since the average length of a is 300-400.
b = a.filter((i, idx) => {
return idx % 2 == 0;
});
a = a.filter((i, idx) => {
return idx % 2 == 1;
});
I've also been looking at lodash to see if that library had anything that might help me and the only function that's near what I'm looking for is _.chunk(array, \[size=1\]).
I appreciate any and all help to help me figure out a better, faster way to do this.
Since you mentioned lodash you could do this with _.partition:
let a = [1, 2, 3, 4, 5, 6];
let b = [];
let i = -1;
[a, b] = _.partition(a, (item) => i++ % 2);
console.log(a);
console.log(b);
<script src="https://cdn.jsdelivr.net/lodash/4.17.4/lodash.min.js"></script>
Partition's predicate is the identity function, which doesn't include the index of the item, so this comes with a compromise of an external index i.
Of course, you could always wrap this functionality into it's own function:
const splitEvenOdd = (array, i = -1) => _.partition(array, (item) => i++ % 2);
let a = [1, 2, 3, 4, 5, 6];
let b = [];
[a, b] = splitEvenOdd(a);
console.log(a);
console.log(b);
<script src="https://cdn.jsdelivr.net/lodash/4.17.4/lodash.min.js"></script>
Vanilla JS ES5, simple and clean.
var a = [1, 2, 3, 4, 5, 6], b = [];
for(var i = a.length-1; i >= 0; i--) {
if(i % 2 === 1) {
b.unshift(a.splice(i, 1)[0])
}
}
Basically, it is iterating through a backwards, and if the condition is true splicing the item und adding it as first item of b.
To loop through the source once, the values can be added to a specific array depending on the index. For example:
const source = [1, 2, 3, 4, 5, 6];
let arrs = [[],[]];
for(let i = 0; i< source.length; i++)
arrs[i%2].push(source[i]);
let [a,b] = arrs;
console.log(a);
console.log(b);
Alternatively, if it's important to alter the original arrays, a can be filled in a direct iteration, since the index being processed is always ahead of the one being filled:
let a = [1, 2, 3, 4, 5, 6], b= [];
for(let i = 0; i< a.length; i++)
(i % 2 ? b : a)[Math.floor(i/2)] = a[i];
a.splice(a.length/2);
console.log(a);
console.log(b);
The best performance you can get for this is 0(n) or linear time since you have to iterate through the entire array. What may help is reducing the number of loops
var a=[];
var b=[];
function splitArray(arr)
{
for (var i=0;i<arr.length;++i)
{
if (arr[i]%2 == 0)
b.push(arr[i]);
else
a.push(arr[i]);
}
}
What this does is reduces the number of times you have to iterate through the original array from 2 to 1
Related
I wrote a solution that allows me to get an array of indexes from the first array which is the intersection of indexes from two sorted arrays and I'd like to know why this solution is wrong. When I check it I get the correct array of indexes from the first array but the interviewer told me that this is wrong.
Thanks a lot for the help and explanations. I have no commercial experience yet. Sorry for some mistakes in English, as I am from Ukraine and I improve this language.
// first example of input:
// const arr1 = [1, 2, 2, 2];
// const arr2 = [1, 1, 2, 2];
// second example of input:
const arr1 = [1, 2, 2, 3, 4, 5, 6, 7, 9, 9, 20];
const arr2 = [1, 2, 3, 3, 5, 8, 9, 9, 21];
// first example of output:
// - [0, 1, 2]
// - [0, 1, 3]
// - [0, 2, 3]
// second example of output:
// - [0, 1, 3, 5, 8, 9]
// - [0, 2, 3, 5, 8, 9]
//function compareItemsFn, length1, length2 - from conditions to this task
const compareItemsFn = (index1, index2) => {
switch (true) {
case arr1[index1] === arr2[index2]: return 0;
case arr1[index1] < arr2[index2]: return -1;
case arr1[index1] > arr2[index2]: return 1;
default: return undefined;
}
};
const length1 = arr1.length;
const length2 = arr2.length;
// function intersectionIndexes - my solution
function intersectionIndexes(compareItemsFn, length1, length2) {
let indexesIntersectionArray = [];
let i = 0;
let j = 0;
while (i < length1 && j < length2) {
if (compareItemsFn (i, j) === 0) {
indexesIntersectionArray.push(i);
i++;
j++;
} else if (compareItemsFn (i, j) === 1) {
j++;
} else {
i++;
}
}
return indexesIntersectionArray;
};
const result = intersectionIndexes(compareItemsFn, length1, length2);
If you are certain that your solution works then perhaps it was not wrong in the sense that it gave the wrong answer but rather in the way you solved the problem.
The following code is a simplification of your solution. It takes the two arrays as parameters instead of the value of their length property so the solution isn't tied to the global variables arr1 and arr2. You should always favor implementing solutions that are generalised.
In place of your compareItemsFn function, the Math.sign() method from the standard library is used. Some times in interview situations you can be asked to implement functionality which can be found in the standard library and what the interviewer is looking to see is if you are aware of it.
function simplified(arrayOne, arrayTwo) {
let result = [];
let indexOne = 0;
let indexTwo = 0;
while (indexOne < arrayOne.length && indexTwo < arrayTwo.length) {
let signCheck = Math.sign(arrayOne[indexOne] - arrayTwo[indexTwo]);
if (signCheck == 0) {
result.push(indexOne);
indexOne++;
indexTwo++;
}
else if ( signCheck > 0) {
indexTwo++;
}
else {
indexOne++;
}
}
return result;
}
const numbers = [2, 4, 5, 2, 3, 5, 1, 2, 4];
I need to create the function indexOfRepeatedValue (array). Use numbers that are stored in the variable numbers.
I should create a variable firstIndex in this function. In the for loop, check which number repeats first and assign its index to firstIndex. Then write this variable to the console - outside of the for loop.
I came up with this idea It doesn't work at all. I'm lost, some piece of advice?
const numbers = [2, 4, 5, 2, 3, 5, 1, 2, 4];
function indexOfRepeatedValue(array) {
let firstIndex;
for (let i = 0; i < array.length; i++)
if (firstIndex.indexOf(array[i]) === -1 && array[i] !== '');
firstIndex.push(array[i]);
return firstIndex;
}
console.log(
indexOfRepeatedValue(numbers)
)
Start by making firstIndex an array: let firstIndex = [];
Then make sure the i is not outside the scope you used since you use let.
You end the statement with a semicolon, that means the loop never does the next line
Then return the first number found that is in your new array
Note JS Arrays start at 0, so the result is 3, since the second number 2 is in the 4th place
I have kept my code as close to yours as possible.
const numbers = [2, 4, 5, 2, 3, 5, 1, 2, 4];
function indexOfRepeatedValue(array) {
let firstIndex = [];
for (let i = 0; i < array.length; i++) {
if (firstIndex.indexOf(array[i]) !== -1) { // we found it
console.log("found",array[i], "again in position", i)
console.log("The first of these is in position",numbers.indexOf(array[i]))
return i; // found - the function stops and returns
// return numbers.indexOf(array[i]) if you want the first of the dupes
}
firstIndex.push(array[i]); // not found
}
return "no dupes found"
}
console.log(
indexOfRepeatedValue(numbers)
)
There are many more ways to do this
Javascript: How to find first duplicate value and return its index?
You could take an object for storing the index of a value and return early if the index exist.
function indexOfRepeatedValue(array) {
let firstIndex = {};
for (let i = 0; i < array.length; i++) {
if (firstIndex[array[i]] !== undefined) return firstIndex[array[i]];
firstIndex[array[i]] = i;
}
return -1;
}
const numbers = [2, 4, 5, 2, 3, 5, 1, 2, 4];
console.log(indexOfRepeatedValue(numbers));
Start by initializing firstIndex:
let firstIndex = [];
Use the following to find the index of each repeated element:
if( array.slice(0,i).includes(array[i]) ) {
firstIndex.push( i );
}
If you need the absolute first index of a repeat:
return firstIndex[0];
//Please note that if this is your goal then you do not even need the variable firstIndex, nor do you need to run through the whole loop.
If you need indices of all repeated elements:
return firstIndex;
const numbers = [2, 4, 5, 2, 3, 5, 1, 2, 4];
function indexOfRepeatedValue(array) {
let firstIndex = [];
for (let i = 0; i < array.length; i++)
if( array.slice(0,i).includes(array[i]) ) {
firstIndex.push(i);
}
return firstIndex[0];
}
console.log(
indexOfRepeatedValue(numbers)
)
NOTE
Alternatively, you can use Array#map to get index of repeated values then use Array#filter to retain only those indices, the first [0] is what you're lookin for.
const numbers = [2, 4, 5, 2, 3, 5, 1, 2, 4];
const indexOfRepeatedValue = arr =>
arr.map((a,i) => arr.slice(0,i).includes(a) ? i : -1)
.filter(i => i > -1)[0];
console.log( indexOfRepeatedValue( numbers ) );
A beginner JS question.. I need to write a function that reverses an array that goes as a function's input. (I cannot use a reverse method).
I wonder why this works:
function reverseArrayInPlace(array) {
for (let i = 0; i < Math.floor(array.length / 2); i++) {
let old = array[i];
array[i] = array[array.length - 1 - i];
array[array.length - 1 - i] = old;
}
return array;
}
let arr = [0, 1, 2, 3, 4, 5];
console.log(reverseArrayInPlace(arr))
But this does NOT:
function reverseArrayInPlace(arr) {
let len = arr.length;
for (counter = 0; counter < 2 * len; counter += 2) {
arr.unshift(arr[counter]);
}
arr = arr.slice(0, len);
}
let b = [0, 1, 2, 3, 4, 5];
console.log(reverseArrayInPlace(b));
Looks like arr = arr.slice(0,len); part is not working..I wonder why when:
b = b.slice(0,6);
[5, 4, 3, 2, 1, 0]
If you want to change the input arrray, avoiding return, use splice:
function reverseArrayInPlace(arr) {
let len = arr.length;
for (counter = 0; counter < 2 * len; counter += 2) {
arr.unshift(arr[counter]);
}
arr.splice(len);
}
var b = [0, 1, 2, 3, 4, 5];
reverseArrayInPlace(b);
console.log(b);
EDIT:
If you want to do something like:
console.log(reverseArrayInPlace(b));
your function MUST return something, otherwise the print will always be undefined, even if b has been reverted
arr = arr.slice(0, len);
slice returns a new array which you store inside the local variable arr, that does not change b, which is still pointing to the whole array. To mutate the array you could:
arr.splice(len, len);
and then you have to return arr to log something meaningful.
Because the array is passed to the function by copying the reference, hence you cannot change the external reference from inside the function.
So I want to create a function in js which takes two arrays and compare them and give a score depending on how many spots in the two arrays match. Is it right or it's bd written. I am new on coding.
Another problem I have is when I try to execute it on chrome's console. It says that compare is not defined
let score = 0;
function compare(arr1, arr2) {
for (let i = 0; i < arr2.length; i++) {
for (let j = 0; j < arr1.length; j++) {
if(arr1[j] === arr2[i]){
score++;
}
}
}
You can use .reduce() to find count of matched elements:
let arr1 = [1, 2, 3, 4, 5],
arr2 = [3, 4, 5, 6, 7],
compare = (a1, a2) => arr1.reduce((a, c) => a + arr2.includes(c), 0);
console.log(compare(arr1, arr2));
Alternatively, you can use .filter() to find array of matched elements and use its length to determine the count.
let arr1 = [1, 2, 3, 4, 5],
arr2 = [3, 4, 5, 6, 7],
compare = (a1, a2) => arr1.filter(v => arr2.includes(v)).length;
console.log(compare(arr1, arr2));
Docs:
Array.prototype.reduce()
Array.prototype.includes()
Array.prototype.filter()
Arrow Functions
This should work for you:
Updated the code as required by you :
let arr1 = [1, 2, 3, 4];
let arr2 = [3,2,3,4,5];
function compare(arr1,arr2){
let count=0;
const max=arr1.length>arr2.length ? arr2.length : arr1.length;
for(var i=0;i<max;i++){
if(arr1[i]==arr2[i]){
count++;
}
}
return count;
}
console.log(compare(arr1,arr2));
How to find the greatest number of times each element occurs in a nested array?
I am looking to find the greatest number of times each element occurs in any of the subarrays. I am NOT looking for the element that occurs the most times in the entire nested array.
Let's say my nested array is [[2, 3, 5], [3, 3, 5], [2, 2, 3, 5]].
The number 2 appears two times in one of the subarrays. The number 3 appears two times in one of the subarrays. The number 5 appears one time in one of the subarrays.
The end result I am looking for is [2, 2, 3, 3, 5].
What is the best way to do this? Below is my approach, which is not very good.
function makeNewArray(arr) {
// add the # to the numbers that appear once and add the ## to the numbers that appear twice
for (var j = 0; j < arr.length; j++) {
for (var i = 0; i < arr[j].length; i++) {
if (arr[j][i] === arr[j][i+1]) {
arr[j][i] = arr[j][i] + '#';
arr[j][i+1] = arr[j][i+1] + '#';
} else {
arr[j][i] = arr[j][i] + '#';
}
}
}
// flatten the array
arr = arr.reduce(function(a, b) { return a.concat(b); });
// remove the duplicates from the array
arr = arr.filter(function(a, b) { return arr.indexOf(a) == b; });
// remove the ## and # from the array
for (var i = 0; i < arr.length; i++) {
arr[i] = parseInt(arr[i]);
}
return arr;
}
makeNewArray([[2, 3, 5], [3, 3, 5], [2, 2, 3, 5]]);
Just based on your question and not the result you expect that I don't really get, here is a working solution that will find the highest number of occurrence.
var a = [
[2, 3, 5],
[3, 3, 5],
[2, 2, 3, 5]
];
var o = {};
var max = 0;
var highest = null;
for (var i = 0; i < a.length; i++) {
for (var j = 0; j < a[i].length; j++) {
if (!o.hasOwnProperty(a[i][j])) {
o[a[i][j]] = 1;
} else {
o[a[i][j]]++;
}
if (o[a[i][j]] > max) {
max = o[a[i][j]];
highest = a[i][j];
}
}
}
//this is the number with the highest occurence
console.log(highest);
This ES6 solution iterates the sub arrays, and creates a map of the values, then in it moves the highest values to a map of the entire array. Afterwards, we map the Map entries (no pan intended) to new arrays that are filled with the numbers according to their highest count, and flatten the result.
var data = [[2, 3, 5], [3, 3, 5], [2, 2, 3, 5]];
var result = [].concat(... // flatten the end result
[... // convert the Map to entries array
data.reduce((r, s) => { // reduce the array into a map of counts
s.reduce((map, num) => map.set(num, (map.get(num) || 0) + 1), new Map) // get a Map of the current sub array counts
.forEach((v, k) => r.set(k, Math.max(r.get(k) || 0, v))); // update the global Map if the sub array count of a number is higher
return r;
}, new Map)]
.map((s) => Array.from({ length: s[1] }, () => s[0]))); // map the entries into new sub arrays
console.log(result);