Related
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(', ')} ]`);
}
Actually I have made this on excel using Vlookup but now I am making this on webpage.
I have a input box where user will enter the value
<input class="text" type="text" name="rawScore" onchange="calcpercentile()">
and I have a span of where user can get the result
<span id="percentile"></span>
I have two arrays
var percentile = [10, 20, 30, 40, 50, 60, 70, 80, 90];
var rawScores = [1, 3, 5, 7, 10, 12, 18, 25, 27];
what code should I write that if I write so I get the
input value
(rawScores) (percentile)
1 10
2 20
3 30
4 40
Your example seems wrong. I expect score 1 to map to the 10th percentile, 2 & 3 to the 20th percentile, and 4 to the 30th percentile.
In essence, I think what you're trying to do is: find the array index of the first raw score that is greater than the input, and return the corresponding value from the percentiles array.
The Javascript could look something like this:
var percentiles = [10, 20, 30, 40, 50, 60, 70, 80, 90];
var rawScores = [1, 3, 5, 7, 10, 12, 18, 25, 27];
function map(input) {
let index = rawScores.findIndex(rawScore => rawScore >= input);
return percentiles[index];
}
console.log(map(1));
console.log(map(2));
console.log(map(3));
console.log(map(4));
Note that browser support for Array#findIndex() is limited. If you need wide browser support, a simple loop-based approach might be better:
var percentiles = [10, 20, 30, 40, 50, 60, 70, 80, 90];
var rawScores = [1, 3, 5, 7, 10, 12, 18, 25, 27];
function map(input) {
for (var i = 0; i < rawScores.length; i++) {
if (rawScores[i] >= input) {
return percentiles[i];
}
}
}
console.log(map(1));
console.log(map(2));
console.log(map(3));
console.log(map(4));
you can input text : 1
span display "10"
window.onload = function(){
var percentile = [0,10, 20, 30, 40, 50, 60, 70, 80, 90];
document.getElementById("rawScore").onchange = function () {
var index = document.getElementById("rawScore").value;
document.getElementById("percentile").innerHTML = percentile[index];
}
}
<input class="text" type="text" id="rawScore">
<span id="percentile"></span>
First you sort your dataset of course
const arr = [0,2,5,2,7,3];
const data = arr.sort();
What may help next, is this function to find the index of the closest number.
console.log(findClosestIndex([0, 1, 2, 3.5, 4.5, 5], 4));
// output: 3
console.log(findClosestIndex([0, 1, 2, 3.49, 4.5, 5], 4));
// output: 4
console.log(findClosestIndex([0, 1, 2, 3.49, 4.5, 5], 90));
// output: 5
console.log(findClosestIndex([0, 1, 2, 3.49, 4.5, 5], -1));
// output: 0
function findClosestIndex(arr, element) {
let from = 0, until = arr.length - 1
while (true) {
const cursor = Math.floor((from + until) / 2);
if (cursor === from) {
const diff1 = element - arr[from];
const diff2 = arr[until] - element;
return diff1 <= diff2 ? from : until;
}
const found = arr[cursor];
if (found === element) return cursor;
if (found > element) {
until = cursor;
} else if (found < element) {
from = cursor;
}
}
}
So, now you know your index and the length of your array. And you have to get a percentile from that. Let's first calculate an exact percentage.
const index = findClosestIndex(data, input);
const pct = index / arr.length;
Turning this percentage into a percentile is a matter of rounding it.
const percentile = (Math.floor(pct/10)+1) * 10;
(PS: I use this function for buying/selling stocks when their current price is in a certain percentile of the daily transaction price rates.)
I am trying to interchange array and print it using shift method but not sure whether I can use it or not.
Code Snippet below.
var points = [40, 100, 1, 5, 25, 10];
//trying to achieve like anotherPoints array
//var anotherPoints = [1, 5, 100, 40, 25, 10];
for (index = 0; index < points.length; index++) {
points.shift();
console.log(points);
}
Some logic to get the desired result:
var points = [40, 100, 1, 5, 25, 10],
temp1 = [], temp2 = [], anotherArray;
points.forEach(function(val){
if(val < 10 ) {
temp1.push(val)
} else {
temp2.push(val);
}
});
anotherArray = temp1.sort().concat(temp2.sort(function(a,b){return b- a}));
alert(anotherArray);
It's not possible via shift or splice. Unless manually creating the array.
The shift() method doesn't shift or interchange the elements of an Array. It is similar to pop(), but it pops out the first element from the Array.
For example,
var points = [40, 100, 1, 5, 25, 10];
console.log(points.shift()); // 40
console.log(points); // [100, 1, 5, 25, 10]
As to your requirement of rearranging the elements of an Array, you will have to use Array.splice() method. Check out this question Reordering arrays.
Sup fellow geeks!
I'm trying to make an array that lists all the possible values of the sums of the elements of an array. I'm sure this must be quite easy but I'm up to 2 or 3 hours now and I'm getting frustrated, I think I'm almost there...
var frootVals = [0,1,2,3,4,5]
var frootInc = frootVals
var fruitEnd = frootInc[frootInc.length-1]//begins at 5
var fruitAll = 15 // The total of all the numbers in the array. (this is actually
// calculated in another function, but lets just say I declared it as 15)
for (e = frootVals.length-2 ;fruitEnd !== fruitAll;e--){ //so I want it to
//finish when the final array entry is 15.
for (p = 1;p < e; p++){
var incEnd = frootInc[frootInc.length-p]
frootInc.push(incEnd + frootVals[p]) //1st time round (5 + 1 = 6, 5 + 2 = 7,
//5 + 3 =8, 5 + 4 = 9) THEN start again with 9 now being incEnd so pushes
//9+1 = 10 etc etc until the last digit is 15 and the whole loop stops...
}
}
EDIT - Basically the final result I'm after is frootInc to be be an array of the integers [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15] - I'm sure I'll kick myself for giving up but I've only been learning a few weeks so this is all quite brain taxing.
After thinking about your question a bit, I think the easiest solution would be with recursion when the condition that the final value added to the array is less than the sum of values.
Here's a JS Fiddle for demo: http://jsfiddle.net/ukgzwpky/
To break it down a bit (and so that you may confirm I have the question right :D), say we have the following array:
[0, 1, 2, 3, 10, 15, 30]
The sum of the values are: 61. So the expected output array would be:
[0, 1, 2, 3, 10, 15, 30, 31, 32, 33, 40, 45, 46, 47, 48, 55, 60, 61]
To further break it down, the looping logic would do something like this:
// Get final value to add to previous values
var val = [0, 1, 2, 3, 10, 15, 30].pop();
// Add the final value - 30 - to all previous values (ignoring the zero)
.. loop here and push the values to our array ...
// For the first iteration, the updated array looks like:
[0, 1, 2, 3, 10, 15, 30, 31, 32, 33, 40, 45]
// New values calculated from: 30 + 1, 30 + 2, 30 + 3, 30 + 10, 30 + 15
At this point, our max value of 61 is less than the final value of 45 So, we do it again!
var val = [0, 1, 2, 3, 10, 15, 30, 31, 32, 33, 40, 45].pop();
.. loop here and push the values to our array ...
// Second iteration, the updated array looks like:
[0, 1, 2, 3, 10, 15, 30, 31, 32, 33, 40, 45, 46, 47, 48, 55, 60, 61]
// New values are: 45 + 1, 45 + 2, 45 + 3, 45 + 10, 45 + 15
// Note that 45 + 30 would be greater than our sum of 61, so we break
If that's correct, here's a script that I wrote that populates such an array:
function getPopulatedArray(arr) {
var max = arguments[1] || getSum(arr),
current = arr.pop(),
temp = [],
i = 1,
len = arr.length;
// Populate temp array with values
for (; i < len; i++) {
if ((arr[i] + current) < max) {
temp.push(arr[i] + current);
} else {
temp.push(max);
break;
}
}
arr.push(current);
arr = arr.concat(temp);
// Done? Or should we continue?
if (arr[arr.length - 1] < max) {
return getPopulatedArray(arr, max);
} else {
return arr;
}
}
Again, the JS fiddle for demonstration: http://jsfiddle.net/ukgzwpky/
Hopefully this helps!
A very simple solution would be to do something like this:
var frootVals = [0,1,2,3,4,5]
var result = [];
for (var i = 0; i < frootVals.length; i++){ // Iterate over the array twice
for (var j = 0; j < frootVals.length; j++){ // To calculate all combinations
result.push(frootVals[i] + frootVals[j]);
}
}
Now, if you don't want duplicates, try this:
var frootVals = [0,1,2,3,4,5]
var result = [];
for (var i = 0; i < frootVals.length; i++){
for (var j = 0; j < frootVals.length; j++){
var value = frootVals[i] + frootVals[j];
if(result.indexOf(value) === -1){
result.push(value);
}
}
}
You could then use result = result.sort() if you want to output a sorted result.
I have 7 arrays in javascript and I need to find values that are present in all of them.
I don't think I'm the first one to ask this but I can't find a solution for this. I read many answers but they all compare only 2 arrays and that logic don't work for multiple arrays.
I tried functions proposed in Simplest code for array intersection in javascript but they don't fit the kind of arrays I have.
The arrays I have can have different lengths in elements and the element's lengtt can vary too. I also may have zero item arrays in which they should not be compared against.
The main problem is with different number lengths. All functions I tried require sorting but this causes a problem.
Given this arrays:
xnombre = [1,2,3,4,5,24,44,124,125,165];
xacomp = [1,5,44,55,124];
xeje = [];
xanio = [1,5,44,55,124];
xini = [1,5,44,55,124];
xaporte = [1,5,44,55,122,123,124,144,155,166,245];
xpcia = [2,1,3,4,6,5,7,9,12,12,14,15,44,16,17,19,124];
The first to arrays are sorted to:
[1, 124, 125, 165, 2, 24, 3, 4, 44, 5]
[1, 124, 44, 5, 55]
Which when I "intersect" I only get [1,124] but 44 and 5 are missed.
Any help would be appreciated.
Thanks
The function from the other question works, but you have to sort your array numerically, not lexicographically, since you are working with numbers, not strings.
function sortNumber(a,b) {
return a - b;
}
var xnombre = [1,2,3,4,5,24,44,124,125,165];
var xacomp = [1,5,44,55,124];
xnombre.sort(sortNumber);
xacomp.sort(sortNumber);
DEMO
To apply this to multiple arrays, you could apply this function consecutively:
// var result = intersect(a, b, c, ...);
function intersect(var_args) {
// sort arrays here or beforehand
var target = arguments[0];
for (var i = 1; i < arguments.length; i++) {
if (arguments[i].length > 0) {
target = intersection_safe(target, arguments[i]);
}
}
return target;
}
This requires some of the new array methods, but it produces your desired output.
function intersection() {
var arrs = Array.prototype.filter.call(arguments, function (a) {
return a.length > 0;
}).sort(function (a, b) { // sort the arrays, so that we test the shortest.
return a.length - b.length;
});
var rest = arrs.slice(1),
test = arrs[0];
return test.filter(function (x) { return rest.every(function (a) { return a.indexOf(x) !== -1; }); });
}
var xnombre = [1, 2, 3, 4, 5, 24, 44, 124, 125, 165],
xacomp = [1, 5, 44, 55, 124],
xeje = [],
xanio = [1, 5, 44, 55, 124],
xini = [1, 5, 44, 55, 124],
xaporte = [1, 5, 44, 55, 122, 123, 124, 144, 155, 166, 245],
xpcia = [2, 1, 3, 4, 6, 5, 7, 9, 12, 12, 14, 15, 44, 16, 17, 19, 124];
intersection(xnombre, xacomp, xeje, xanio, xini, xaporte, xpcia)
// => [1, 5, 44, 124]
I tried your problem with underscore.
var _ = require('underscore');
xnombre = [1,2,3,4,5,24,44,124,125,165];
xacomp = [1,5,44,55,124];
xeje = [];
xanio = [1,5,44,55,124];
xini = [1,5,44,55,124];
xaporte = [1,5,44,55,122,123,124,144,155,166,245];
xpcia = [2,1,3,4,6,5,7,9,12,12,14,15,44,16,17,19,124];
var result = _.intersection(xnombre,xacomp,xanio,xini,xaporte,xpcia);
console.log(result);
But as you see that I haven't given the empty array, so somehow you have to ignore empty array.
Fiddle