I am trying to add the values of multiple arrays at each index.
Eg.
arr1 = [100, 110, 121]
arr2 = [20, 25, 27.5]
newArr = [120, 135, 148.5]
My current approach is below.
I am finding the percentage change between stocks each day (Day 1, Day 2, Day 3 etc)
Then I am moving to the next stock and I want to add the percentage change of stock 1 and stock 2 together. ie Append the new percentage change to the old percentage change.
What I am trying to do know is check if the index exists as a key in the object, and if it does, add the diff figure to this index.
If the index doesn't exist I want to just add the diff figure.
It is working when the index doesn't exist but when the index does exist (ie. The second, third stock etc) the old value for that index is just overwritten with the newer value.
I want to add them together.
Is there a simple clean solution for this?
accumPercent = {}
const portfolio = props.test.map((item) => {
let oldPrice = item.res.data.o[0]
item.res.data.o.map((item1, index) => {
let diff = ((item.res.data.c[index] - oldPrice) / oldPrice) * 100
oldPrice = item.res.data.c[index]
if (index in Object.keys(accumPercent)) {
accumPercent[index] = accumPercent[index] + diff
} else {
accumPercent[index] = diff
}
})
})
let example = [
{
o: [10, 20, 30]
},
{
o: [10, 40, 60]
}
]
You can use map like this:
const arr1 = [100, 110, 121]
const arr2 = [20, 25, 27.5]
const newArr = arr1.map((i, idx) => i + arr2[idx])
// result: [120, 135, 148.5]
Or if the arrays are in an object:
const test = {arr1: [100, 110, 121], arr2: [20, 25, 27.5]}
const newArr = test.arr1.map((i, idx) => i + test.arr2[idx])
// result: [120, 135, 148.5]
One more way :
let fr = []
arr1.forEach((d,index)=>{
fr.push(d + arr2[index])
})
console.log(fr)
Related
split() does mutate the array.
filter() really remove all elements with the filtered name in array.
Lets say there are two arrays:
listOfPrices = [15, 30, 10, 20, 10]
declinedItems = [0, 2]
So, I want to create a certain array, in Python I can just use
annaItem = [item for item in listOfPrices]
for item in declinedItems:
annaItem.remove(listOfPrices[item])
If I print annaItem, the result will be [30, 20, 10]
Here is what I have tried in JS
let annaItem = listOfPrices.map(item => {
return item
})
for (let item in declinedItems) {
console.log(item)
annaItem = annaItem.filter(e => e !== listOfPrices[declinedItems[item]])
}
console.log(annaItem)
The result will be [30, 20].
Why js is so hard..? Plzzz help me
You can use filter, it provides a second argument which is the index so in your case you would do
const listOfPrices = [15, 30, 10, 20, 10];
const declinedItems = [0, 2];
const result = listOfPrices.filter((price, index) => {
return !declinedItems.includes(index);
});
// --
const p = document.getElementById("result");
p.textContent = JSON.stringify(result);
<p id="result"></p>
I was given this problem at one of my interviews and was told I have 20 minutes to solve it. This is the answer I came up with ( 2 versions ). Can you let me know which version you prefer and why, and if you have a better idea of how to solve it (less complex, less memory usage, etc.) Please share.
Problem: You have an array of random numbers that range from 0 to 100 elements.
Write a function that will split this array into several arrays, each containing elements in the following range: (0-10],(10-20],(20-30], etc up to a 100].
Write a function that outputs these arrays in a form of a simple graph, where each delimiter represents a single value in the array.
Array = [10, 12, 71, 52, 51, 1, 5, 22, 21, 6, 95, 11, 3, 64, 45, 55,
65, 42, 99, 4];
Desired outcome:
5 Elements in array: ***** - 1,5,6,3,4
3 Elements in array: *** - 10,12,11
2 Elements in array: ** - 22,21
No Elements in array.
2 Elements in array: ** - 45,42
3 Elements in array: *** - 52,51,55
2 Elements in array: ** - 64,65
1 Elements in array: * - 71
No Elements in array.
2 Elements in array: ** - 95,99
// Version 1
arr = [10, 12, 71, 52, 51, 1, 5, 22, 21, 6, 95, 11, 3, 64, 45, 55, 65, 42, 99, 4];
const splitArray = (inputArray, range) => {
const newArray = [];
do {
let tempArray = [];
tempArray = inputArray.filter((item) => {
if (item >= range && item < range + 10) return item;
});
range += 10;
newArray.push(tempArray);
} while (range + 10 <= 100);
return newArray;
};
const printArrays = (array, delimiter) => {
let toPrint = "";
for (index in array) {
let stars = array[index].length;
let string = "";
for (let i = stars; i > 0; i--) {
string += delimiter;
}
toPrint += stars
? `${stars} Elements in array: ${string} - ${array[index]} \n`
: "No Elements in array. \n";
}
return toPrint;
};
console.log(printArrays(splitArray(arr, 0), "*"));
// Version 2
arr = [10, 12, 71, 52, 51, 1, 5, 22, 21, 6, 95, 11, 3, 64, 45, 55, 65, 42, 99, 4];
const getArrays = (inputArray) => {
const newArray = [];
let min = 0;
let max = 10;
do {
const tempArray = [];
for (i in arr) {
let val = arr[i];
val >= min && val < max ? tempArray.push(val) : "";
}
min += 10;
max += 10;
newArray.push(tempArray);
} while (max <= 100);
return newArray;
};
const printArrays = (array, delimiter) => {
for (index in array) {
let stars = array[index].length;
let string = "";
for (let i = stars; i > 0; i--) {
string += delimiter;
}
console.log(
stars ? `${stars} Elements in array: ${string} - ${array[index]}` : "No Elements in array."
);
}
};
printArrays(getArrays(arr), "^");
Both approaches have moderate issues.
The first approach does
let tempArray = [];
tempArray = inputArray.filter((item) => {
if (item >= range && item < range + 10) return item;
});
Better to just declare the tempArray as the filtered array to begin with.
const tempArray = inputArray.filter(...
Also, return item is suspicious inside a filter - all the filter callback cares about is whether its return value is truthy or falsey. Returning the array item when you actually want to indicate that the value should be included in the output is a common mistake. It happens not to be a problem here because 0 isn't a possibility, but it's still confusing. A better choice would be to do
const tempArray = inputArray.filter(
item => item >= range && item < range + 10
);
(and maybe rename range to startOfRange)
Both of your approaches are also iterating through the entire input array multiple times (once for each range), which seems a bit wasteful - better to iterate through the input once.
Your second approach uses for (i in arr), and both approaches are doing for (index in array). This is a bad idea, and since you don't actually care about the index you're iterating over, it'd make sense to use for..of loops instead.
I think a better looking approach that iterates through the input just once would be:
const arr = [10, 12, 71, 52, 51, 1, 5, 22, 21, 6, 95, 11, 3, 64, 45, 55, 65, 42, 99, 4];
const getArrays = (inputArray) => {
const grouped = {};
for (let i = 0; i < 100; i += 10) {
grouped[i] = [];
}
for (const item of inputArray) {
const rangeProp = Math.floor(item / 10) * 10;
grouped[rangeProp].push(item);
}
return Object.values(grouped);
};
const printArrays = (groupedArrays, delimiter) => {
for (const array of groupedArrays) {
const stars = delimiter.repeat(array.length);
console.log(
stars
? `${array.length} Elements in array: ${stars} - ${array.join(',')}`
: "No Elements in array."
);
}
};
printArrays(getArrays(arr), "*");
I will do that this way :
This approach is simple: it retrieves the values one by one and adds them to the array corresponding to their range.
const arr = [10, 12, 71, 52, 51, 1, 5, 22, 21, 6, 95, 11, 3, 64, 45, 55, 65, 42, 99, 4];
let ranges = arr.reduce((a,x)=>
{
let range = (x/10)|0 // get range start value 0 to 9
a[range] ??= [] // create the array of if it does not already exist
a[range].push(x)
return a
},{})
console.log('ranges=', ranges ) // so that noobs can visualize this result
for (let r = 0; r < 10; r++ )
{
if (!ranges[r])
document.write('No Elements in array.<br>')
else
{
let count = ranges[r].length
document.write(`${count} Elements in array: ${'*'.repeat(count)} - ${ranges[r].join(',')}<br>`)
}
}
.as-console-wrapper {max-height: 100% !important; width:20%; top: 0;
margin-left: 80%; }
.as-console-row::after {display: none !important;}
range = (x/10)|0 // get range start value 0 to 9
example in case of x = 25 -> 25/10 give 2.5 and 2.5 | 0 give 2 -> integer part value of 2.5
| is the OR boolean operator, work only on integers values so it return an interger
??= is Logical nullish assignment
I'm looking for an easy way to do the following:
I have an array of random numbers between 0-99. I need two arrays, first which have values which share the same first digit, second for values that share the same second digit. It doesn't matter what that digit is, as long as it occurs more than once. 0-9 is to be treated as if the first digit was 0.
To illustrate the problem:
[0, 10, 20, 11, 19, 12, 54, 64, 23, 24] would result in [10, 11, 12, 19, 23, 24] and [0, 10, 20, 24, 54, 64]. Some values can go in both arrays if they meet the criteria.
I've found solutions that are useful if you know the digit you're comparing. However, not in this scenario.
I know the way to begin is to convert numbers inside the array into strings: array.map(String), so that the second and first digit can be accessed by first[0], second[1]. I don't know how to proceed from there, though. Any ideas are greatly appreciated.
You can group your array based on first digit and last digit in an object accumulator. Then, filter the grouped array based on length.
const input = [0, 10, 20, 11, 19, 12, 54, 64, 23, 24],
groupLastDigits = input.reduce((r, n) => {
const last = n % 10;
r[last] ??= [];
r[last].push(n);
return r;
}, {}),
groupFirstDigits = input.reduce((r, n) => {
let first = Math.floor(n / 10);
if(first === n) first = 0;
r[first] ??= [];
r[first].push(n);
return r;
}, {}),
getNumbers = o => Object.values(o).filter(arr => arr.length > 1).flat()
commonLastDigits = getNumbers(groupLastDigits),
commonFirstDigits = getNumbers(groupFirstDigits);
console.log(commonLastDigits);
console.log(commonFirstDigits);
I'd like to offer a generic solution for n digits!
let matchingDigitGroups = function*(arr) {
// Note that very large numbers will convert to string
// in scientific notation, breaking this approach
let maxDigits = Math.max(...arr.map(num => `${num}`.length));
let strs = arr.map(num => {
let str = `${num}`;
while (str.length < maxDigits) str = `0${str}`;
return str;
});
for (let i = 0; i < maxDigits; i++) {
let result = [];
for (let n = 0; n <= 9; n++) {
let matchDigits = strs.filter(str => str[i] === `${n}`);
if (matchDigits.length > 1) result.push(...matchDigits);
}
yield result;
}
};
let tests = [
[ 0, 10, 20, 11, 19, 12, 54, 64, 23, 24 ],
[ 100, 200, 300 ],
[ 111, 222, 333, 771, 828, 399 ],
[],
[ 1 ],
[ 92929, 91919 ]
];
for (let arr of tests) {
console.log(`Groups for: [ ${arr.join(', ')} ]`);
for (let group of matchingDigitGroups(arr)) console.log(` [ ${group.join(', ')} ]`);
}
This question already has answers here:
JavaScript: Rearrange an array in order – largest, smallest, 2nd largest, 2nd smallest, 3rd largest, 3rd smallest,
(4 answers)
Closed 2 years ago.
I need help with the sorting as i am totally confused what to do. This is the example:
[1, 65, 3, 52, 48, 63, 31, -3, 18, 56] to [-3, 65, 1, 63, 3, 56, 18, 52, 31, 48].
The first element has to be the smallest, the second to be biggest, the third to be the second smallest element, the fourth to be the second biggest element.
What i have tried is:
function solve(arr) {
var lowestNum = [...arr].sort((a,b) => a-b);
let biggestNum = [...arr].sort((a,b) => b-a);
let nums = [];
let i = 0;
while (nums.length !== arr.length) {
nums.push(lowestNum.shift()); lowestNum.pop();
nums.push(biggestNum.shift()); biggestNum.pop();
i++;
}
return nums;
}
console.log(solve([1, 65, 3, 52, 48, 63, 31, -3, 18, 56]));
However, that is not the way as my exercise requires me to sort.
This isnt the most elegant solution, but:
let a = [11, 2, 3, -22, 41];
function bigSmallSorter(arr) {
// Sort a copy of the passed in array from least to most.
let sortedArr = [...arr.sort((n, k) => n - k)];
let newArr = [];
let flip = true;
for( let i of arr ) {
let temp = flip
// Take first element of the sorted array
? sortedArr.shift()
// Take the last element of the sorted array
: sortedArr.pop();
// Add the newest value to the value that is ultimately returned
newArr.push(temp);
// Flip this so the next iteration takes from the other
// end of the array
flip = !flip;
}
// Profit
return newArr;
}
console.log(bigSmallSorter(a))
//>[ -22, 41, 2, 11, 3 ]
And an version of the method without comments:
let a = [11, 2, 3, -22, 41];
function bigSmallSorter(arr) {
let sortedArr = [...arr.sort((n, k) => n - k)]
let newArr = [];
let flip = true;
for( let i of arr ) {
let temp = flip
? sortedArr.shift()
: sortedArr.pop()
newArr.push(temp)
flip = !flip;
}
return newArr;
}
console.log(bigSmallSorter(a))
I have the following array:
let numbers = [10, 20, 20, 10, 10, 30, 50, 10, 20];
I create a new array without the duplicate values:
let counter = [...new Set(array)];
//Output: [ 10, 20, 30, 50 ]
I want to instantiate the counter array as a 2D/nested array so that it looks like this:
//counter output: [[10,4][20, 3][30, 1][50,1]]
What's the best way to do this? The numbers array could have various elements and therefore the number of elements in the counter array could vary.
This answer is for the original question (how to create an array of [[10, 0],[20, 0],[30, 0],[50, 0]] from the Set):
Instead of spreading the Set, use Array.from() to create an array of pairs:
const numbers = [10, 20, 20, 10, 10, 30, 50, 10, 20];
const counter = Array.from(new Set(numbers), v => [v, 0]);
console.log(counter);
Assuming you actually want that second sub-array index to represent the number of occurrences of each number (ed: confirmed now), you can collect the counts into a Map and then convert that to an array
let numbers = [10, 20, 20, 10, 10, 30, 50, 10, 20];
const counter = [...numbers.reduce((map, n) =>
map.set(n, (map.get(n) ?? 0) + 1), new Map())]
console.info(JSON.stringify(counter)) // stringifying so it's all on one line
The array conversion works since Map supports the common entries format of
[ [ key, value ], [ key, value ], ... ]
and using spread syntax implicitly converts it to an entries array.
One way is take the ideas you have already used and map across those values returning new arrays with the value and an additional zero.
let numbers = [...new Set([10, 20, 20, 10, 10, 30, 50, 10, 20])].map(value=>[value,0]);
You can convert your original array into an object (hash map) to keep track of the count. And then convert it into to Object.entries() array.
const numbers = [10, 20, 20, 10, 10, 30, 50, 10, 20];
let obj = {};
numbers.forEach(n => {
obj[n] = obj[n] || 0;
obj[n]++;
});
const counter = Object.entries(obj).map(e => [+e[0], e[1]]);
console.log(counter);