Related
I have some array of numbers:
var arr = [1, 7, 1, 4];
I want to increase only every first value, such that the expected output would be: [2, 7, 2, 4]
I tried some combination of map and filter but I don't understand how it can work together...
var mapuj = arr.map(x => x *2);
You can use map() and use second argument which is idnex to determine if it's at event index or not
let arr = [1, 7, 1, 4];
let output = arr.map((n, index) => index % 2 === 0 ? n * 2 : n);
console.log(output);
I'm a newbie to all of this and trying to improve myself by solving problems and challenges.
I came across a problem whereby I have an unordered array which contains 8 integers.
eg [2,3,1,4,6,5,8,7]
I need to sort it [1,2,3,4,5,6,7,8] and reorder the array so that the array starts with the end value and then the first value and so on eg [8,1,7,2,6,3,5,4,]
I worked out I could use map() to iterate across the array and then use push() with pop() and shift() however it leaves the last 2 numbers behind in the original array and I'm not sure why. I got around this by using a concat and a reverse but I still don't understand why pop and shift don't bring across all the elements.
Code below that doesn't pull all the elements:
const reorder = (array) => {
let store = []
array.sort((a, b) => a - b).map((item, i) => {
if (array) {
store.push(array.pop())
store.push(array.shift())
}
})
return store
}
reorder([2, 3, 1, 4, 6, 5, 8, 7]) // returns [8,1,7,2,6,3]
Code that works but I have to add a concat and a reverse:
const reorder = (array) => {
let store = []
array.sort((a, b) => a - b).map((item, i) => {
if (array) {
store.push(array.pop())
store.push(array.shift())
}
})
return store.concat(array.reverse())
}
reorder([2, 3, 1, 4, 6, 5, 8, 7]) //returns [8,1,7,2,6,3,5,4]
Thanks for any help
I would just bisect the array, sort them in opposite orders and then add each element from each array to a new array
Given that you want to then take the sorted bisected arrays and produce another single array, I'd then use Array.prototype.reduce:
const alternatingSort = function (array) {
array = array.sort();
const midpoint = Math.round(array.length / 2)
let arr1 = array.slice(0, midpoint);
let arr2 = array.slice(midpoint);
arr2 = arr2.sort(function (a, b) { return b - a });
return arr1.reduce(function (retVal, item, index) {
arr2[index] && retVal.push(arr2[index]);
retVal.push(item);
return retVal;
}, []);
}
console.log(alternatingSort([2, 3, 1, 4, 6, 5, 8, 7]));
console.log(alternatingSort([2, 3, 1, 4, 6, 5, 8])); // with odd number
As I've seen nobody explained why the original OP solution doesn't work, Here is why:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/
Map calls a provided callback function once for each element in an array, in order, and constructs a new array from the results. callback is invoked only for indexes of the array which have assigned values (including undefined).
It is not called for missing elements of the array; that is:
1.Indexes that have never been set;
2.which have been deleted; or
3.which have never been assigned a value.
So what is happening in our code is that:
On the first iteration,
[(2), 3, 1, 4, 6, 5, 8, 7]
Map picks the first element(2) in the array, and delete the first and last characters in the array, so the array becomes
[3,(1), 4, 6, 5, 8]
Now, as map will not consider deleted elements, the second element(1) in the current array is called, also the first and last element in also removed:
[1, 4,(6), 5]
Now, map is trying to find the third element(6), and delete the first and last element:
[4,6]
Now, map is trying to find the fourth element, which is out of bound, so the map function will terminate.
So, you are strongly advised not to use Array.prototype.shift or Array.prototype.pop in Array.prototype.map.
You can do it following way:
const reorder = (array) => {
array.sort((a, b) => a - b);
const result = [];
const length = array.length;
for (let i = 0; i < length; i++) {
if (i % 2 === 0) {
result.push(array.pop());
} else {
result.push(array.shift());
}
}
return result;
}
const result = reorder([2, 3, 1, 4, 6, 5, 7]);
console.log(result);
Notice that I've intentionally made the array length to be an odd number. Some of the solutions here will break if the length is an odd number.
Personally I would sort, split in half and then just insert in. Not very fancy, but gets the job done.
function strangeWeave (arr) {
var sorted = arr.slice().sort()
var result = sorted.splice(0,Math.floor(sorted.length/2))
for (let i=0;sorted.length;i+=2) {
result.splice(i,0,sorted.pop())
}
return result
}
console.log(strangeWeave([1,2]))
console.log(strangeWeave([1,2,3]))
console.log(strangeWeave([1,2,3,4,5,6,7,8]))
console.log(strangeWeave([1,2,3,4,5,6,7,8,9]))
There is a much easier solution to sort two different arrays, one normal and one in reverse, then connect them together. Here is the code for that:
var myArray = [1, 3, 2, 4, 5, 7, 6, 8];
function getCopy(arr) {
var x = [];
for(var i = 0; i < arr.length; i++)
x.push(arr[i]);
return x;
}
function sortMyWay(arr) {
var sortedArr = [],
leftSide = getCopy(arr).sort()
.splice(0, Math.ceil(arr.length / 2)),
rightSide = getCopy(arr).sort().reverse()
.splice(0, Math.floor(arr.length / 2));
for(var i = 0; i < arr.length; i++)
i % 2
? sortedArr.push(leftSide[Math.floor(i / 2)])
: sortedArr.push(rightSide[Math.floor(i / 2)]);
console.log(sortedArr);
return sortedArr;
}
var sortedArr = sortMyWay(myArray);
Hope it helped!
Happy coding :)
I have an array of values. I want to make a second array based on the first one with stricter criteria. For example, what I want specifically is:
arrayOne[1,1,1,1,1,2,2,2,3,3,3,3,4,4,4,4,4,5,5,5]
How would I make it so in my new array, only the values that show up 5 times are a part of the array and only show up once. Example: arrayTwo [1,4]
I'm fairly new to JavaScript and have been given an opportunity to code a decision making system for one of my business courses instead of doing the final exam. Any help you can give would be much appreciated. Thank You.
You could use a hash table, which counts each found element and then use the count for filtering and get only the fifth element as result set in a single loop.
var array = [1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5],
count = Object.create(null),
result = array.filter(v => (count[v] = (count[v] || 0) + 1) === 5);
console.log(result);
I commented the code with the steps I took:
const arrayOne = [1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5];
function method(arr, minimum) {
//Create an object containing the amount each number occurs
const occurrences = arr.reduce((o, n) => {
//If number is already in the object add 1
if (o[n]) o[n] = o[n] + 1;
//Else set its occurence to 1
else o[n] = 1;
//Return the object for the next iteration
return o;
}, {});
//Deduplicate the array be creating a Set(every elements can only occur once) and spread it back into an array
const deduplicate = [...new Set(arr)];
//Filter array to only contain elements which have the minimum of occurences
const filtered = deduplicate.filter(n => occurrences[n] >= minimum);
return filtered;
}
console.log(method(arrayOne, 5));
You can use a Map for this.
let arrayOne = [1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5];
let counterMap = new Map();
arrayOne.forEach(value => {
let valueStr = value.toString();
counterMap.set(valueStr, counterMap.has(valueStr) ? counterMap.get(valueStr) + 1 : 1);
});
let arrayTwo = [];
counterMap.forEach((value, key, map) => {
if(value >= 5) {
arrayTwo.push(key);
}
});
console.log(arrayTwo);
Not the most elegant answer, but I assume you're looking just to find all values that appear at least 5 times.
const arrayOne = [1,1,1,1,1,2,2,2,3,3,3,3,4,4,4,4,4,5,5,5]
const arrayTwo = Object.entries(arrayOne.reduce((obj, num) => {
if(!obj[num]){
obj[num] = 1
} else {
obj[num] = obj[num] + 1
}
return obj
}, {})).filter(([key, value]) => {
return value >= 5
}).map((item) => {
return parseInt(item[0])
})
console.log(arrayTwo)
const a = [1,1,1,1,1,2,2,2,3,3,3,3,4,4,4,4,4,5,5,5,5,5,5,5,5,5];
Define a function that will take an array and numOfOccurrences
const filterByOcur = (arr, numOfOccurrences) => {
// create an object to act as a counter this will let us
// iterate over the array only once
const counter = {};
const res = new Set();
for (let num of arr) {
// if it's the first time we see the num set counter.num to 1;
if (!counter[num]) counter[num] = 1;
// if counter.num is greater or equal to numOfOccurrences
// and we don't have the num in the set add it to the set
else if (++counter[num] >= numOfOccurrences && !res.has(num)) res.add(num);
}
// spread the Set into an array
return [...res];
};
console.log(
filterByOcur(a, 5)
);
There is number of ways of doing this, I will try to explain this step by step:
Array declaration
const a = [1,1,1,1,1,2,2,2,3,3,3,3,4,4,4,4,4,5,5,5]
Method to count elements in an array, we are using reducer function that as a first argument takes object where key is our value from array and has a incremental number as a value. Remeber to start reducer with empty object
const counted = a.reduce((counter, value) => {
if (counter[value]) counter[value]++
else counter[value] = 1
return counter
}, {})
Make your array unique with Set constructor
const uniq = Array.from(new Set(a))
Fire filter functions on the uniq array with a help of counted array, look how we access it:
const onlyOne = uniq.filter(val => counted[val] === 1)
const onlyFive = uniq.filter(val => counted[val] === 5)
Merge all filtered arrays into one
const final = [].concat(onlyOne, onlyFive)
If i have an array A = [1, 4, 3, 2] and B = [0, 2, 1, 2] I want to return a new array (A - B) with values [1, 2, 2, 0]. What is the most efficient approach to do this in javascript?
const A = [1, 4, 3, 2]
const B = [0, 2, 1, 2]
console.log(A.filter(n => !B.includes(n)))
Use map method
The map method takes three parameters in it's callback function like below
currentValue, index, array
var a = [1, 4, 3, 2],
b = [0, 2, 1, 2]
var x = a.map(function(item, index) {
// In this case item correspond to currentValue of array a,
// using index to get value from array b
return item - b[index];
})
console.log(x);
For Simple and efficient ever.
Check here : JsPref - For Vs Map Vs forEach
var a = [1, 4, 3, 2],
b = [0, 2, 1, 2],
x = [];
for(var i = 0;i<=b.length-1;i++)
x.push(a[i] - b[i]);
console.log(x);
const A = [1, 4, 3, 2]
const B = [0, 2, 1, 2]
const C = A.map((valueA, indexInA) => valueA - B[indexInA])
console.log(C) // [1, 2, 2, 0]
Here the map is returning the substraction operation for each number of the first array.
Note: this will not work if the arrays have different lengths
If you want to override values in the first table you can simply use forEach method for arrays forEach. ForEach method takes the same parameter as map method (element, index, array). It's similar with the previous answer with map keyword but here we are not returning the value but assign value by own.
var a = [1, 4, 3, 2],
b = [0, 2, 1, 2]
a.forEach(function(item, index, arr) {
// item - current value in the loop
// index - index for this value in the array
// arr - reference to analyzed array
arr[index] = item - b[index];
})
//in this case we override values in first array
console.log(a);
One-liner using ES6 for the array's of equal size in length:
let subResult = a.map((v, i) => v - b[i]); // [1, 2, 2, 0]
v = value, i = index
function subtract(operand1 = [], operand2 = []) {
console.log('array1', operand1, 'array2', operand2);
const obj1 = {};
if (operand1.length === operand2.length) {
return operand1.map(($op, i) => {
return $op - operand2[i];
})
}
throw new Error('collections are of different lengths');
}
// Test by generating a random array
function getRandomArray(total){
const pool = []
for (let i = 0; i < total; i++) {
pool.push(Math.floor(Math.random() * total));
}
return pool;
}
console.log(subtract(getRandomArray(10), getRandomArray(10)))
Time Complexity is O(n)
You can also compare your answer with a big collection of arrays.
This question already has an answer here:
Start from second item in forEach loop
(1 answer)
Closed 5 years ago.
Can this be done without mutating the array?
let arr = [1, 2, 3, 4, 5];
arr.shift() // works but mutates the array
arr.forEach(function(value) {
console.log(value)
});
2
3
4
5
You could use Array#slice for a copy without the first element.
let arr = [1, 2, 3, 4, 5];
arr.slice(1).forEach(function(value) {
console.log(value);
});
Use index in the forEach:
let arr = [1, 2, 3, 4, 5];
arr.forEach(function(value, index) {
if ( index != 0 ) {console.log(value) }
});
Though array.slice(1).forEach(...) is elegant, it does create a new array. You can avoid doing this by checking whether the second property passed to forEach (the array index) is 0, or "falsy." If your passed function happens to only execute a single expression, you can shorten the statement:
if (i) expression() to i && expression()
...which makes this method surprisingly terse.
let array = [1, 2, 3, 4, 5]
array.forEach(function (value, i) {
if (i) console.log(value)
})
array.forEach(function (value, i) {
i && console.log(value)
})
let arr = [1, 2, 3, 4, 5];
arr.forEach(function(value, index) {
return index == 0 ? true : console.log(value), true;
});
arr.forEach(function(value, index) {
if(index !== 0) {
console.log(value);
}
});
this little if statement just fires if the value is not equal to the first array item