How to change a number to text in javascript - javascript

i currently have something which rolls onto a number but i'd like to change it so instead of displaying the number it rolled on, it displays the name which the number is apart of. A snippet of what i have is below:
function spin(m) {
var x = m.roll;
play_sound("roll");
var order = [1, 14, 2, 13, 3, 12, 4, 0, 11, 5, 10, 6, 9, 7, 8];
var index = 0;
for (var i = 0; i < order.length; i++) {
if (x == order[i]) {
index = i;
break
}
}
var max = 32;
var min = -32;
var w = Math.floor(m.wobble * (max - min + 1) + min);
var dist = index * 70 + 36 + w;
dist += 1050 * 5;
animStart = new Date().getTime();
vi = getVi(dist);
tf = getTf(vi);
isMoving = true;
setTimeout(function() {
finishRoll(m, tf)
}, tf);
render()
}
As you can see I have 1, 14, 2, 13 etc.
I would like it so if it rolls onto 1, 2, 3, 4, 5, 6 or 7 it shows 'Group1' instead of the number it has landed on.
The same goes with 14, 13, 12, 11, 10, 9 and 8 except i'd like it to show 'Group2' instead of the number it has landed on.
Now for 0, i'd like it so it shows 'Green' instead of 0 when it lands on it.
These are the main snippets in the file.
1.
function cd(ms, cb) {
$("#counter").finish().css("width", "100%");
$("#counter").animate({
width: "0%"
}, {
"duration": ms * 1000,
"easing": "linear",
progress: function(a, p, r) {
var c = (r / 1000).toFixed(2);
$BANNER.html("Rolling in " + c + "...");
},
complete: cb
});
}
2.
function finishRoll(m, tf) {
$BANNER.html("Rolled number " + m.roll + "!");
addHist(m.roll, m.rollid);
play_sound("finish");
for (var i = 0; i < m.nets.length; i++) {
$("#panel" + m.nets[i].lower + "-" + m.nets[i].upper).find(".total").countTo(m.nets[i].swon > 0 ? m.nets[i].swon : -m.nets[i].samount, {
"color": true,
"keep": true
});
}
var cats = [
[0, 0],
[1, 7],
[8, 14]
];
for (var i = 0; i < cats.length; i++) {
var $mytotal = $("#panel" + cats[i][0] + "-" + cats[i][1]).find(".mytotal");
if (m.roll >= cats[i][0] && m.roll <= cats[i][1]) {
$mytotal.countTo(m.won, {
"color": true,
"keep": true
});
} else {
var curr = parseFloat($mytotal.html());
if ($("#settings_dongers").is(":checked")) {
curr *= 1000;
}
$mytotal.countTo(-curr, {
"color": true,
"keep": true
});
}
}
if (m.balance != null) {
$("#balance").countTo(m.balance, {
"color": true
});
checkplus(m.balance);
}
setTimeout(function() {
cd(m.count);
$(".total,.mytotal").removeClass("text-success text-danger").html(0);
$(".betlist li").remove();
snapRender();
$(".betButton").prop("disabled", false);
showbets = true;
}, m.wait * 1000 - tf);
}
3.
function snapRender(x, wobble) {
CASEW = $("#case").width();
if (isMoving) return;
else if (typeof x === 'undefined') view(snapX);
else {
var order = [1, 14, 2, 13, 3, 12, 4, 0, 11, 5, 10, 6, 9, 7, 8];
var index = 0;
for (var i = 0; i < order.length; i++) {
if (x == order[i]) {
index = i;
break
}
}
var max = 32;
var min = -32;
var w = Math.floor(wobble * (max - min + 1) + min);
var dist = index * 70 + 36 + w;
dist += 1050 * 5;
snapX = dist;
view(snapX)
}
}

How about this?
// assumes n is always a number between 0 and 14 (inclusive)
function numberToName(n) {
if (n === 0) {
return "Green";
} else if (n < 8) {
return "Group1";
} else {
return "Group2";
}
}
Just call this with the chosen number and then use the returned text however you want.

Related

Grouping items in groups of 7 and 8 javascript

Code:
const fs = require("fs");
const { parse } = require("csv-parse");
function getSchedule() {
let schedule = [];
fs.createReadStream("./timetable.csv")
.pipe(parse({ delimiter: ",", from_line: 2 }))
.on("data", function (row) {
let classp = "ΘΗΨ3β";
// Get all items for the students classes and put them in a variable
for (let i = 0; i < row.length; i++) {
if (row[i].includes(classp) || row[i].includes("ΓΘ2Φ5-3") || row[i].includes("ΓΘ1Μ7-3")) {
schedule.push({ number: i, text: row[i] });
}
}
// Filtering to put the items in order
for (let i = 0; i < schedule.length; i++) {
if (schedule[i + 1]) {
if (schedule[i].number > schedule[i + 1].number) {
let temp = schedule[i];
schedule[i] = schedule[i + 1];
schedule[i + 1] = temp;
}
}
}
let numberOfObjects = 8 // <-- decides number of objects in each group
// Group items from schedule into groups of 8
let groupedProducts = schedule.reduce((acc, elem, index) => {
let rowNum = Math.floor(index / numberOfObjects) + 1;
acc[`${rowNum}`] = acc[`${rowNum}`] || [];
acc[`${rowNum}`].push(elem);
return acc
}, {});
console.log(groupedProducts)
});
}
getSchedule();
Output:
{
'1': [
{ number: 3, text: 'ΓΘ1Μ7-3 / 16 / Μαθηματικά Εμβ. 4-ωρ 04ΓΘΚ' },
{ number: 4, text: 'ΘΗΨ3β / 24 / Ψηφ.Ηλεκτρονικά II Γ ΘΗΥ' },
{ number: 5, text: 'ΘΗΨ3β / 24 / Ψηφ.Ηλεκτρονικά II Γ ΘΗΥ' },
{ number: 6, text: 'ΓΘ2Φ5-3 / 53 / Φυσική ΘΓΚ3-Μ6' },
{ number: 7, text: 'ΘΗΨ3β / 11 / Νέα Ελληνικά ΘΓΚ3-Μ1 Γ' },
{ number: 8, text: 'ΘΗΨ3β / 11 / Νέα Ελληνικά ΘΓΚ3-Μ1 Γ' },
{ number: 9, text: 'ΘΗΨ3β / 138α / Θρησκευτικά ΘΓΚ3-Μ1 Γ' },
{
number: 10,
text: 'ΘΗΨ3β / 118 / Εφαρμ.Προγραμ. ΙΙΙ Γ ΘΗΨ'
}
],
.....
'5': [
{ number: 37, text: 'ΓΘ1Μ7-3 / 16 / Μαθηματικά Εμβ. 4-ωρ 04ΓΘΚ' },
{
number: 39,
text: 'ΘΗΨ3β / 112 / Μικροελ. Ρομποτική Γ ΘΗΨ'
},
{
number: 40,
text: 'ΘΗΨ3β / 118 / Εφαρμ.Προγραμ. ΙΙΙ Γ ΘΗΨ'
},
{
number: 41,
text: 'ΘΗΨ3β / 118 / Εφαρμ.Προγραμ. ΙΙΙ Γ ΘΗΨ'
}
]
}
Basically what I want is to have 8 elements in the first one and 4th one and 7 in the 2nd 3rd and 5th but currently it adds 8 in all of them and 3 or 4 in the last. I tried multiple solutions like if statements and forcing an empty element in between the last and first of each element but I didn't seem to succeed.
const fs = require("fs");
const { parse } = require("csv-parse");
function getSchedule() {
let schedule = [];
fs.createReadStream("./timetable.csv")
.pipe(parse({ delimiter: ",", from_line: 2 }))
.on("data", function (row) {
let classp = "ΘΗΨ3β";
// Get all items for the students classes and put them in a variable
for (let i = 0; i < row.length; i++) {
if (row[i].includes(classp) || row[i].includes("ΓΘ2Φ5-3") || row[i].includes("ΓΘ1Μ7-3") || row[i].includes("ΓΘ2Φ1-3")) {
schedule.push({ number: i, text: row[i] });
}
}
// Filtering to put the items in order
for (let i = 0; i < schedule.length; i++) {
if (schedule[i + 1]) {
if (schedule[i].number > schedule[i + 1].number) {
let temp = schedule[i];
schedule[i] = schedule[i + 1];
schedule[i + 1] = temp;
}
}
}
// Group items from schedule into groups of 8
let groupSizes = [8, 7, 7, 8, 7];
let start = 0;
let result = [];
for (let size of groupSizes) {
result.push(schedule.slice(start, start + size));
start += size;
}
console.log(result)
});
}
getSchedule();

How can I interpolate zeroes sequences in a number array?

let's say I have an arbitrary number sequence
let sequence = [
0, 0, 0, 0, 0,
12, 64, 9, 6,
0, 0, 0,
25, 79, 57, 13, 39,
0, 0,
7, 7,
0, 0, 0, 0, 0,
49,
0
];
I need to replace all zeroes with interpolation given from non-zeroes neighbours, so the output would be
let output = [
12, 12, 12, 12, 12,
12, 64, 9, 6,
10.75, 15.5, 20.25,
25, 79, 57, 13, 39,
28.3333, 17.6666,
7, 7,
14, 21, 28, 35, 42,
49,
49
];
While firs zeroes [0, 4] doesn't have left neighbour all their values have to be 12, while last zero has only right resident 49, it would be just 49.
For me, it doesn't really a problem to fill parts where both left and right neighbours are presented, however I'm looking for an universal and elegant solution for this task.
const interpolateValues = (array, index0, index1, left, right) => {
let n = index1 - index0 + 1;
let step = (right - left) / (n + 1);
for(let i = 0; i < n; i++){
array[index0 + i] = left + step * (i + 1);
}
}
const findZerosSequences = (array) => {
var counter = 0;
var index = 0;
var result = [];
for (let i = 0; i < array.length; i++) {
if (array[i] === 0) {
index = i;
counter++;
} else {
if (counter !== 0) {
result.push([index - counter + 1, index]);
counter = 0;
}
}
}
if (counter !== 0) { result.push([index - counter + 1, index]); }
return result;
}
let sequence = [
0, 0, 0, 0, 0,
12, 64, 9, 6,
0, 0, 0,
25, 79, 57, 13, 39,
0, 0,
7, 7,
0, 0, 0, 0, 0,
49,
0
];
//[[0,4], [9, 11], [17, 18], [21, 25], [27, 27]]
let zeroes = findZerosSequences(sequence);
for(let i = 0; i < zeroes.length; i++){
let lf = sequence[zeroes[i][0] - 1];
let rf = sequence[zeroes[i][1] + 1];
if(lf !== undefined && rf !== undefined && lf > 0 && rf > 0){
interpolateValues(sequence, zeroes[i][0], zeroes[i][1], lf, rf);
}
}
console.log(sequence);
let output = [
12, 12, 12, 12, 12,
12, 64, 9, 6,
10.75, 15.5, 20.25,
25, 79, 57, 13, 39,
28.3333, 17.6666,
7, 7,
14, 21, 28, 35, 42,
49,
49
];
You almost got it, let the interpolateValues worry about those edge cases which are easily resolved.
let sequence = [
0, 0, 0, 0, 0,
12, 64, 9, 6,
0, 0, 0,
25, 79, 57, 13, 39,
0, 0,
7, 7,
0, 0, 0, 0, 0,
49,
0
];
const interpolateValues = (array, index0, index1, left, right) => {
if (left === null) left = right;
if (right === null) right = left;
if (left === null && right === null) left = right = 0;
let n = index1 - index0 + 1;
let step = (right - left) / (n + 1);
for (let i = 0; i < n; i++) {
array[index0 + i] = left + step * (i + 1);
}
}
const findZerosSequences = (array) => {
var counter = 0;
var index = 0;
var result = [];
for (let i = 0; i < array.length; i++) {
if (array[i] === 0) {
index = i;
counter++;
} else {
if (counter !== 0) {
result.push([index - counter + 1, index]);
counter = 0;
}
}
}
if (counter !== 0) {
result.push([index - counter + 1, index]);
}
return result;
}
let zeroes = findZerosSequences(sequence);
for (let i = 0; i < zeroes.length; i++) {
let lf = zeroes[i][0] - 1 >= 0 ? sequence[zeroes[i][0] - 1] : null;
let rf = zeroes[i][1] + 1 < sequence.length ? sequence[zeroes[i][1] + 1] : null;
interpolateValues(sequence, zeroes[i][0], zeroes[i][1], lf, rf);
}
console.log(sequence);
If anyone would be interested in spaghetti instead of a valid answer :)
const sequence = [
0, 0, 0, 0, 0,
12, 64, 9, 6,
0, 0, 0,
25, 79, 57, 13, 39,
0, 0,
7, 7,
0, 0, 0, 0, 0,
49,
0
]
const output = sequence.join(',')
.replace(/^([0,]+)(\d+)/, (_, zeros, number) => {
const n = zeros.match(/0/g).length
return (number + ',').repeat(n) + number
})
.replace(/([^0,]+),([0,]+)([^0,]+)/g, (_, number1, zeros, number2) => {
const n = zeros.match(/0/g).length
const diff = +number2 - +number1
const step = diff / (n + 1)
return number1 + ',' + [...Array(n).keys()].map(i => {
const val = +number1 + (i + 1) * step
return Math.floor(val * 10000) / 10000
}) + ',' + number2
})
.replace(/(\d+)([,0]+)$/, (_, number, zeros) => {
const n = zeros.match(/0/g).length
return number + (',' + number).repeat(n)
}).split(',').map(Number);
console.log(output)
I would keep track of the start and end values when looping over looking for non zeros. When it is the start the starting index will not be set so you know it needs to be the first value. You can loop one extra index and you know it will be the end. For the others it will be the step like you did.
let sequence = [
0, 0, 0, 0, 0,
12, 64, 9, 6,
0, 0, 0,
25, 79, 57, 13, 39,
0, 0,
7, 7,
0, 0, 0, 0, 0,
49,
0
];
let startIndex = -1;
for (var i = 0; i <= sequence.length; i++) {
if (sequence[i] !== 0) {
if (i - startIndex > 1) {
let func;
const startVal = sequence[startIndex];
const endVal = sequence[i];
if (startIndex === -1) {
func = () => endVal;
} else if (i === sequence.length) {
func = () => startVal;
} else {
func = (j) => {
return startVal + (endVal - startVal) / (i - startIndex) * j;
}
}
for (let j = 1; j < i - startIndex; j++) {
sequence[j + startIndex] = func(j);
}
}
startIndex = i;
}
}
console.log(sequence);
Other way is set the start and end and do the calculation
let sequence = [
0, 0, 0, 0, 0,
12, 64, 9, 6,
0, 0, 0,
25, 79, 57, 13, 39,
0, 0,
7, 7,
0, 0, 0, 0, 0,
49,
0
];
let startIndex = -1;
for (var i = 0; i <= sequence.length; i++) {
if (sequence[i] !== 0) {
if (i - startIndex > 1) {
const startVal = startIndex === -1 ? sequence[i] : sequence[startIndex];
const endVal = i === sequence.length ? startVal : sequence[i];
const func = (j) => {
return startVal + (endVal - startVal) / (i - startIndex) * j;
}
for (let j = 1; j < i - startIndex; j++) {
sequence[j + startIndex] = func(j);
}
}
startIndex = i;
}
}
console.log(sequence);
Haven't checked my sample, but you should see the way I guess..
let sequence = [
0, 0, 0, 0, 0,
12, 64, 9, 6,
0, 0, 0,
25, 79, 57, 13, 39,
0, 0,
7, 7,
0, 0, 0, 0, 0,
49,
0
];
let temporaryZerosArray = [];
for (const [id, value] of sequence.entries()) {
if (value) {
if (!temporaryZerosArray.length) continue;
temporaryZerosArray.splice(0, temporaryZerosArray.length - 2);
let [one, two] = temporaryZerosArray;
let lf = sequence[one-1]
let rf = sequence[two+1]
if (
(!!lf && lf > 0) &&
(!!rf && rf > 0)
) interpolateValues(sequence, one,two, lf , rf );
temporaryZerosArray = [];
continue
}
temporaryZerosArray.push(id);
}
Here's a solution that accepts your input array and returns the interpolated output array. I put comments inline with the code to explain how it works. This solution also behaves correctly for arrays of all zeros.
function interpolateArray(input) {
let output = []; // New array for output
let zeros = 0; // Count of sequential zeros
let start = 0; // Starting number for interpolation
for (let i = 0; i < input.length; i++) { // Loop through all input values
let value = input[i]; // Current input value
if (value === 0) zeros++; // If value is zero, increment the zero count
else { // If the value is non-zero...
if (start === 0) start = value; // If the starting value is zero, set start to current non-zero value
if (zeros) { // If there are zeros accumulated...
let step = (value - start) / (zeros + 1); // Compute the step value (current value, minus start, divided by total steps)
for (let j = 1; j <= zeros; j++) output.push(start + (j * step)); // For each zero, push the stepped value to output
zeros = 0; // Reset zero count
}
start = value; // Store the current value as the new start
output.push(start); // Push the current non-zero value to output
}
}
for (let j = 0; j < zeros; j++) output.push(start); // If there are accumulated zeros, that means they were trailing. Push last non-zero value to output for each
return output; // Return the output
}
Update:
Just for fun, I tightened up the code a bit so the function is more compact. It works exactly the same.
function interpolateArray(input) {
let output = [], zeros = 0, start = 0;
input.forEach(value => {
if (value) {
start = start || value;
if (zeros) {
let step = (value - start) / (zeros + 1);
while (zeros--) output.push(start += step);
zeros = 0;
}
output.push(start = value);
} else zeros++;
});
while (zeros--) output.push(start);
return output;
}

Converting to Roman Numerals in Javascript - Weird bug

function convertToRoman(num) {
var thisMap = {
1:[1],
2:[1, 1],
3:[1, 1, 1],
4:[1, 5],
5:[5],
6:[5, 1],
7:[5, 1, 1],
8:[5, 1, 1, 1],
9:[1, 10],
0:[0]
};
var numMap = {
1000:"M",
500:"D",
100:"C",
50:"L",
10:"X",
5:"V",
1:"I"
};
numArr = num.toString().split("");
var thisIndex = 1;
var tallyArr = [];
for (var i = numArr.length - 1; i >= 0; i--) {
tallyArr.unshift(thisMap[numArr[i]]);
}
thisIndex = Math.pow(10, tallyArr.length - 1);
checkArr = [];
<<<BUG HERE>>>
for (var x = 0; x < tallyArr.length; x++) {
for (var y = 0; y < tallyArr[x].length; y++) {
tallyArr[x][y] *= thisIndex;
}
thisIndex = thisIndex / 10;
}
<<</BUG HERE>>>
var finalArr = [];
for (var a = 0; a < tallyArr.length; a++) {
for (var b = 0; b < tallyArr[a].length; b++) {
finalArr.push(numMap[tallyArr[a][b]]);
}
}
finalAnswer = finalArr.join("");
return finalAnswer;
}
convertToRoman(88);
So this is my function for converting a number into a Roman Numeral in Javascript. It basically formats every number into the right format using thisMap, then uses thisIndex to multiply by either 1000, 100 or 10, and then compares to numMap to get the correct Roman Numeral.
It seems to work in most of the test cases, except with 44, 99, or 3999.
In these cases, it seems to multiply the numbers by the wrong amount, so 44 becomes XLXL, when it should be XLIV.
I think the bug is between the <<>> tags I've inserted, because that is where the numbers seem to be multiplied wrong.
However, I can't spot the problem.
Thanks.
I tried a different approach.
function convertToRoman(num) {
let arabicArray = [ 1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000, 4000, 5000, 5001]
let romanArray = ['I', 'IV', 'V', 'IX', 'X', 'XL', 'L', 'XC', 'C', 'CD', 'D', 'CM', 'M', 'MV', 'V', 'limit of 5000']
let roman = ""
loop()
function loop() {
for (let i = 0; i < arabicArray.length; i++) {
if (num < arabicArray[i]) {
roman += romanArray[i - 1]
num -= arabicArray[i - 1]
while (num != 0) {loop()} break;
}
}
}
return roman
}
console.log(convertToRoman(3))
However this gives you a limit to 5000.
Try this: x loop should run through all the length of tallyArr except the last one.
function convertToRoman(num) {
// ... code ...
for (var x = 0; x < tallyArr.length - 1; x++) {
for (var y = 0; y < tallyArr[x].length; y++) {
tallyArr[x][y] *= thisIndex;
}
thisIndex = thisIndex / 10;
}
// ... more code ...
}
Your solution seems a bit over engineered and overly complicated sometimes simpler is better and what might seem like a clever answer and looking for the overly eloquent solution can trip you up.
function convertToRoman(num) {
var output = "";
var numMap = [
{ limit: 1000, value: "M" },
{ limit: 900, value: "CM" },
{ limit: 500, value: "D" },
{ limit: 400, value: "CD" },
{ limit: 100, value: "C" },
{ limit: 90, value: "XC" },
{ limit: 50, value: "L" },
{ limit: 40, value: "XL" },
{ limit: 10, value: "X" },
{ limit: 9, value: "IX" },
{ limit: 5, value: "V" },
{ limit: 4, value: "IV" },
{ limit: 1, value: "I" }
];
for(var index = 0; index < numMap.length; index++) {
var value = numMap[index].value,
limit = numMap[index].limit;
while(num >= limit) {
output += value;
num -= limit;
}
}
return output;
}
alert(convertToRoman(1));
alert(convertToRoman(4));
alert(convertToRoman(5));
alert(convertToRoman(9));
alert(convertToRoman(10));
alert(convertToRoman(88));
alert(convertToRoman(2016));
JSFiddle
var romanNumber = [
[1, 'I'], [2, 'II'], [3, 'III'],[4, 'IV'],
[5, 'V'], [6, 'VI'],[7, 'VII'], [8, 'VIII'],
[9, 'IX'],[10, 'X']
];
function convertToRoman(number) {
if (number === 0) {
return '';
}
for (var i = 0; i < romanNumber.length; i++) {
if (number === romanNumber[i][0]) {
return romanNumber[i][1];
}
}
}
console.log(convertToRoman(1));
console.log(convertToRoman(2));
console.log(convertToRoman(3));
console.log(convertToRoman(4));
console.log(convertToRoman(5));
console.log(convertToRoman(6));
console.log(convertToRoman(7));
console.log(convertToRoman(8));
console.log(convertToRoman(9));
console.log(convertToRoman(10));

Linear arrangement algorithm

I am not sure if title is correct.
I have few labels which have set their positions in y scale in range:
range = [0, 100px]
for example: 5 labels in positions:
positions = [5px, 6px, 8px, 72px, 76px]
Now I want my algorithm to correct these positions to not let them be closer than 10px to each other and do minimal corrections.
I am expecting calling my function like this:
result = calculateNewPositions(range, positions, min(10px, 100px / positions.length))
and result in this case should be:
[0px, 10px, 20px, 69px, 79px]
What is name of this alghoritm or how to implement that?
Here's an algorithm that should work pretty well for most cases, and tries to make as minimal amount of adjustments as necessary from the original values.
Iterate through each pair of elements.
If the space is not large enough, move them apart from each other by 1, making sure not to violate the range.
Repeat until all the elements have enough space between them.
And here is a sample implementation:
function calculateNewPositions(positions, minSpacing, rangeMin, rangeMax) {
var temp = positions.slice(0);
var madeChange;
do {
madeChange = false;
for (var i = 0; i < temp.length - 1; i++)
if (temp[i + 1] - temp[i] < minSpacing) {
if (temp[i] > rangeMin) { temp[i]--; madeChange = true; }
if (temp[i + 1] < rangeMax) { temp[i + 1]++; madeChange = true; }
}
} while (madeChange);
return temp;
}
Demo: https://jsfiddle.net/aaxmuw2t/
Example Result: [0, 10, 20, 69, 79]
Note that this algorithm is very simplistic and may not always yield the best result for really complex arrays with lots of close numbers. For example, if you input [33, 34, 35, 36], you get [19, 29, 40, 50], which has an extra unnecessary space.
calculateNewPositions = function(positions, minDelta) {
var newPositions = [0]
positions.slice(1).forEach(function(pos, index) {
var delta = positions[index + 1] - positions[index]
newPositions.push(newPositions[index] + Math.max(delta, minDelta))
})
return newPositions
}
https://tonicdev.com/lipp/pos-diff
I finally did something like this:
var fixPositions = function(range, pos, delta, strict) {
var i;
var leftSpaces = [];
var halfDelta = strict ? delta / 2 : 0;
delta = Math.min(delta, (range[1] - range[0] / (pos.length + (strict ? 0 : 1))));
// calculate all spaces that are greater than delta
leftSpaces.push(Math.max(pos[0] - range[0] - halfDelta, 0));
for (i = 1; i < pos.length; i++) {
leftSpaces.push(Math.max(pos[i] - pos[i-1] - delta, 0));
}
leftSpaces.push(Math.max(range[1] - pos[pos.length-1] - halfDelta, 0));
// save indexes of big spaces
var nonZeroSpacesIdx = [];
leftSpaces.map(function(space, i) {
if (space > 0) {
nonZeroSpacesIdx.push(i);
}
});
// sort indexes by spaces sizes (start from smaller)
nonZeroSpacesIdx.sort(function(a, b) {
return leftSpaces[a] - leftSpaces[b];
});
// loop until spaces sum are greater than range
var spacesSum = Infinity;
while (nonZeroSpacesIdx.length > 0 && spacesSum > 0) {
spacesSum = 0;
for (i = 0; i < nonZeroSpacesIdx.length; i++) {
spacesSum += leftSpaces[nonZeroSpacesIdx[i]];
}
var missingDiff = (spacesSum + (pos.length - 1) * delta + halfDelta * 2) - (range[1] - range[0]);
if (missingDiff <= 0) {
break;
}
// find min diff which can be substracted from all spaces
var minDiff = Math.min(missingDiff / nonZeroSpacesIdx.length, leftSpaces[nonZeroSpacesIdx[0]]);
for (i = 0; i < nonZeroSpacesIdx.length; i++) {
leftSpaces[nonZeroSpacesIdx[i]] -= minDiff;
}
// remove index of first space if its equal zero
if (leftSpaces[nonZeroSpacesIdx[0]] <= 0) {
nonZeroSpacesIdx.shift();
}
}
// reconstruct new positions
var newPos = [];
newPos.push(range[0] + leftSpaces[0] + halfDelta);
for (i = 1; i < leftSpaces.length - 1; i++) {
newPos[i] = newPos[i-1] + leftSpaces[i] + delta;
}
return newPos;
};
// result should be from range: [5, 95]
console.log(fixPositions([0, 100], [5, 6, 8, 72, 76], 10, true));
// result should be from range: [0, 100]
console.log(fixPositions([0, 100], [5, 6, 8, 72, 76], 10, false));
https://jsfiddle.net/fcwu1oyu/14/
Its not giving exact same values for my input, but it does the job for my pie charts:
A work in progress solution
The code pushes two too close couples appart with one on each side. This is symetrically and results in sometimes to far pushed values, which can be corrected.
function disperse(values, threshold, range) {
var delta = Array.apply(null, { length: values.length }).map(function () { return 0; }),
converged = false;
while (!converged) {
converged = true;
delta = delta.map(function (d, i, dd) {
if (i < dd.length - 1 && dd.length > 1 && values[i + 1] + dd[i + 1] - values[i] - d < threshold) {
converged = false;
dd[i + 1] += 1;
return d - 1;
}
return d;
});
}
converged = false;
// try to minimise difference
while (!converged) {
converged = true;
delta = delta.map(function (d, i) {
var space;
if (i < delta.length - 2) {
space = values[i + 1] + delta[i + 1] - values[i] - d;
if (d < 0 && space > threshold) {
converged = false;
return d + space - threshold;
}
}
return d;
});
}
// respect lower range
delta.reduce(function (r, d, i, dd) {
if (values[i] + d < r) {
dd[i] = r - values[i];
return r + threshold;
}
return values[i] + threshold + d;
}, range[0]);
// respect upper range
delta.reduceRight(function (r, d, i, dd) {
if (values[i] + d > r) {
dd[i] = r - values[i];
return r - threshold;
}
return values[i] + d;
}, range[1]);
return values.map(function (v, i) {
return v + delta[i];
});
}
document.write('<pre>' + JSON.stringify(disperse([5, 6, 8, 72, 76], 10, [0, 100]), 0, 4) + '</pre>');
document.write('<pre>' + JSON.stringify(disperse([5, 6, 7, 8, 72, 76], 10, [0, 100]), 0, 4) + '</pre>');
document.write('<pre>' + JSON.stringify(disperse([24, 28, 92, 94, 95], 10, [0, 100]), 0, 4) + '</pre>');

Extracting the most duplicate value from an array in JavaScript?

my question is actually similar to: Extracting the most duplicate value from an array in JavaScript (with jQuery)
Solution (the one I found as the best, and slightly changed by me):
var arr = [3, 7, 7, 7, 7, 10, 10, 8, 5, 5, 5, 5, 20, 20, 1],
result = {},
max = 0,
res;
for( var i = 0, total = arr.length; i < total; ++i ) {
var val = arr[i],
inc = ( result[val] || 0 ) + 1;
result[val] = inc;
if( inc > max ) {
max = inc;
res = val;
}
}
alert(res);
I would like to add an extra which is : if we have, say two numbers with the same number of occurrences, how could we find the minimum of them (the above should alert 5 and not 7, which is the case)? The current solution works for getting only the first most duplicate found, but it does not deal with repetition.
Thanks!
Sort the array before you count the incidences:
var arr = [3, 7, 7, 7, 7, 10, 10, 8, 5, 5, 5, 5, 20, 20, 1];
function min_most_duplicate (arr) {
var result = {},
max = 0,
res;
arr = arr.slice(0); // make a copy of the array
arr.sort(function(a, b) { return (a - b); }); // sort it numerically
for( var i = 0, total = arr.length; i < total; ++i ) {
var val = arr[i],
inc = ( result[val] || 0 ) + 1;
result[val] = inc;
if( inc > max ) {
max = inc;
res = val;
}
}
return res;
}
min_most_duplicate(arr); // returns 5
This works because the way the for loop is written it's going to return the first one that it finds that has the most duplicates, so if the array is sorted, the smallest number will come first, so it'll be the one that the for loop finds.
This would work, example:
var arr = [3, 7, 7, 7, 7, 10, 10, 8, 5, 5, 5, 5, 20, 20, 1],
result = {},
max = 0,
res, key, min;
for (var i = 0, total = arr.length; i < total; ++i) {
var val = arr[i],
inc = (result[val] || 0) + 1;
result[val] = inc;
if (inc > max) {
max = inc;
res = val;
}
}
for (var i in result) {
if (result[i] === max) {
key = parseInt(i, 10);
min = min || key;
console.log(min)
if (min > key) {
min = key;
}
}
}
res = min;
alert(res);
let getMostDuplicated = array => {
let duplicated = '';
let max = 0;
for (let i = 0; i < array.length; i++) {
let counter = 0;
for (let j = 1; j < array.length - 1; j++) {
if (array[i] === array[j])
counter++;
}
if (counter > max) {
duplicated = array[i];
max = counter;
}
}
return duplicated;
};
let array = [3, 7, 7, 7, 7, 10, 10, 8, 5, 5, 5, 5, 20, 20, 1];
getMostDuplicated(array);

Categories

Resources