Sorry if this has already been asked but I did search "javascript sort index linked array" and found nothing satisfactory.
I've got an array of names, and another index linked array which records the frequency at which the names appear in a passage, and I want to sort both arrays not alphabetically but according to the name frequencies - say, most frequent to least frequent. I've got the following bit of code which does the job adequately, but I'm thinking that it looks like a hack. Surely there's a more decorous way to solve what must be a pretty common sorting problem.
I start with an array of names[] say, 6 Johns, 2 Annes, 9 Toms, 12 Andrews, 3 Kristens, 1 Archie, and 14 Peters - already sorted alphabetically and counted into frequencies, and the routine below results in an array of indexes to the names and frequency arrays which allows me to display the names and frequencies in order from highest to lowest.
var names = ["Andrew", "Anne", "Archie", "John", "Kristen", "Peter", "Tom"];
var frequency = [12, 2, 1, 6, 3, 14, 9];
var holder = [], secondpart = [], numindex = [];
var i;
for (i = 0; i < frequency.length; i++) {
if (frequency[i] < 10) {
holder[i] = "0" + frequency[i] + "!" + i; // add leading zeros as required
}
if (frequency[i] > 9) {
holder[i] = frequency[i] + "!" + i; // no leading zeros required
}
}
holder.sort();
holder.reverse();
for (i = 0; i < holder.length; i++) {
secondpart[i] = holder[i].substring(holder[i].indexOf("!") + 1, holder[i].length);
numindex[i] = parseInt(secondpart[i]);
}
I can now list both arrays according to the name frequencies.
var txt = "";
var useindex;
for (i = 0; i < numindex.length; i++) {
useindex = numindex[i];
txt = txt + names[useindex] + " - " + frequency[useindex] + "<br>";
}
Has anyone else had this problem and how did you solve it.
try this:
var names = ["Adam", "Peter", "Mahu", "Lala"];
var frequencies = [6,2,9,1];
var tupples=[];
for(let i = 0; i<names.length; i++)
{
tupples[i] = {
frequency : frequencies[i],
name : names[i]
};
}
//ascending
//tupples.sort(function(a,b){return a.frequency-b.frequency;});
//descending
tupples.sort(function(a,b){return b.frequency-a.frequency;});
for(let i=0; i<tupples.length; i++)
{
console.debug(tupples[i].name, tupples[i].frequency);
}
Basically you could use the indices and sort them by getting the the frequency for the given index.
var names = ['Andrew', 'Anne', 'Archie', 'John', 'Kristen', 'Peter', 'Tom'],
frequency = [12, 2, 1, 6, 3, 14, 9],
indices = names.map(function(_, i) { return i; });
indices.sort(function(a, b) {
return frequency[b] - frequency[a];
});
document.write('<pre>' + JSON.stringify(indices, 0, 4) + '</pre>');
document.write(indices.map(function(a) { return names[a]; }).join('<br>'));
Related
I have two arrays villanStrength = [112,243,512,343,90,478] and playerStrength = [5,789,234,400,452,150] of same length, I am comparing each value of array playerStrength with villanStrength and forming up an another array which will store the either 0 or 1 (false or true) based on comparison, but the output array I am getting is not desirable. Please help me...
my code:
process.stdin.resume();
process.stdin.setEncoding('ascii');
var userInput = //providing this externally from the file
1
6
112 243 512 343 90 478
5 789 234 400 452 150;
var testCases = "";
var numberOfPlayers = "";
var villanStrength = [];
var playerStrength = [];
process.stdin.on('data', (data) => {
userInput = data;
// console.log("user input = " + userInput);
let res = userInput.split("\n");
testCases = res[0];
// for (i=1; i<=testCases; i++) {
numberOfPlayers = res[1];
// console.log("cases = " + testCases);
// console.log("number of players = " + numberOfPlayers);
villanStrength = res[2].split(" ");
playerStrength = res[3].split(" ");
console.log("villan Strength = " + villanStrength);
console.log("player Strength = " + playerStrength);
let isSmall = false;
let comparisonResult = [];
for (let j=0; j<villanStrength.length; j++) {
for (let k=0; k<playerStrength.length; k++) {
if (playerStrength[j] < villanStrength[k]) {
comparisonResult[k] = 1; //true = 1, false = 0
} else {
comparisonResult[k] = 0;
}
}
console.log("comparison result for " + j +":" + comparisonResult);
if(comparisonResult.find((findOne) => {return findOne = 1;} )) {
isSmall = true;
console.log("LOSE");
break;
}
}
if (isSmall === false) {
console.log("Win");
}
// }
});
The output array is comparisonResult[] and the values inside comparisonResult I am getting is as below:
villan Strength = 112,243,512,343,90,478
player Strength = 5,789,234,400,452,150
comparison result for 0: 0,0,1,0,1,0 //this should be 1,1,1,1,1,1
comparison result for 1: 0,0,0,0,1,0
comparison result for 2: 0,1,1,1,1,1
comparison result for 3: 0,0,1,0,1,1
comparison result for 4: 0,0,1,0,1,1
comparison result for 5: 0,1,1,1,1,1
in the above result it is expected that the 'comparison result for 0' should be [1,1,1,1,1,1] but it is [0,0,1,0,1,0].
There are a couple problems with this code.
When you compare values in your arrays, you are comparing strings, not numbers. The values you get from stdin are text values, not numeric values. So, for example '5' > '100'. I presume this is the major source of your issue. If you want to do numeric comparisons, you need to convert the strings to numbers.
You are assuming that you get ALL your data on the first data event. While that may usually be true, it is not guaranteed and you should not rely on it when programming. You have to collect data in one or more data events until you have a full chunk of data you can process.
If you add these two log statements that show the actual contents of the array (not the .toString() conversion of the array):
console.log("villan strength: ", villanStrength);
console.log("player strength: ", playerStrength);
You will see this output:
villan strength: [ '112', '243', '512', '343', '90', '478\r' ]
player strength: [ '5', '789', '234', '400', '452', '150;\r' ]
Note, these are strings and when coming from my text file, there's a trailing \r too.
If you change this:
villanStrength = res[2].split(" ");
playerStrength = res[3].split(" ");
to this:
villanStrength = res[2].split(" ").map(item => parseInt(item.trim(), 10));
playerStrength = res[3].split(" ").map(item => parseInt(item.trim(), 10));
Then, it will trim off the newline and convert them to numbers and your comparisons will make sense. This is why the code you posted originally in your question did not generate the wrong output because you hacked in an array of numbers (for purposes of the original question), but your original code was ending up with an array of strings.
Based on your requirement, the playerStrength loop needs to be the outer loop and comparisonResult should be an array of arrays
villanStrength = [112,243,512,343,90,478]
playerStrength = [5,789,234,400,452,150]
// ...
let comparisonResult = []; //output array
for (let j=0; j< playerStrength.length; j++) {
comparisonResult[j] = [];
for (let k=0; k<villanStrength.length; k++) {
if (playerStrength[j] < villanStrength[k]) {
comparisonResult[j].push(1); //true = 1, false = 0
} else {
comparisonResult[j].push(0);
}
}
console.log("comparison result for player " + j +":" + comparisonResult[j]);
}
If I understand the question right you need to compare each value from array1 to array2 and generate a new array that show diffrent...
All you need is just one loop that can take both values and push result of comparison to another array
function compare() {
const villanStrength = [112, 243, 512, 343, 90, 478];
const playerStrength = [5, 789, 234, 400, 452, 150];
const result = [];
for (let i = 0; i < villanStrength.length; i++) {
const vVal = villanStrength[i];
const pVal = playerStrength[i];
if (pVal < vVal) {
result.push(1);
continue;
}
result.push(0);
}
console.log(result);
}
My suggestion for is to separate codes to smaller funtions so you can focus on each section
i'm new in JS and i need your help with some code.
Ok, here's the thing. I'm trying to make a counter for each element of the "names" array.
Here's the code:
var bool = [false, false, false];
var names = ["Banana", "Apple", "Pear"];
var prices = [10, 20, 30]
var sell = ["not purchased!", "not purchased!", "not purchased!"];
var text;
var count = 0;
function checkbuy (names) {
while (text != 0)
{
text = prompt("product list: " + names)
names.sort((a, b) => { return (text.includes(b)) - (text.includes(a)); });
if (names.indexOf(text) >= 0)
{
bool[names.indexOf(text)] = true;
sell[names.indexOf(text)] = "purchased!";
count[names.indexOf(text)] += 1;
alert("Product " + text.toUpperCase() + " is purchased!");
}
for (i = 0; i < names.length; i++)
{
var myList = [ [names[i], prices[i], bool[i], sell[i], count], [names[i], prices[i], bool[i], sell[i], count], [names[i], prices[i], bool[i], sell[i], count ] ];
// alert(myList[i][0]);
alert(names[i] + " " + sell[i] + ", " + bool[i] + count)
}
alert(names);
}
}
I need to enter a value in the prompt, and if it matches the value from the array, then I need to add that item to the list. The addition must occur by using a counter. For example, I enter a value "Banana" in the "prompt field" and the counter value should increase by one. And I need to do so for each element in the array. How can I do that?
Thanks in advance!
You can maintain two arrays, one for list of items and one for their corresponding counter.
For each prompt item, if it matches an item in names, you can increment the corresponding index in sold. Now, in your sold array, anything == 0 is not purchased, and you don't need another array to track that.
var names = ["Banana", "Apple", "Pear"];
var sold = [0, 0, 0];
let exitPrompt = true;
while (exitPrompt) {
let promptVal = prompt('what do you want to buy?');
if (promptVal && promptVal.indexOf('exit') == 0) {
console.log(sold);
break;
} else {
let nameIndex = names.indexOf(promptVal);
if (nameIndex >= 0) {
sold[nameIndex] += 1;
}
}
}
The array I get my original strings from looks something like this:
arr[0]:
11-3
12-6
arr[1]:
5-9
7-2
18-2
arr[2]:
2-7
(That's just an example, the general idea is that there can be any number of objects in arr and the string in each of them contains any number of #-# combos)
I'm trying to add all the numbers on the left together (if using the example above it would add something like 11, 12, 5, 7, 18, and 2 together) and store that number in a variable.
How would I go about this?
Edit 1: attempted code:
var winsLossNums = winLoss[0].match(/\d+/g).map(Number)
for (var i = 0; i < winLoss[0].match(/\d+/g).map(Number).length; i++) {
if (i % 2 === 0) {
totalNums.push(winLoss[0].match(/\d+/g).map(Number)[i]);
}
}
}
This code is in a loop, and every loop there is a new arr object like in the example above
Assuming your array values are strings with a new line between them, you can reduce over the array, split each value on \n and reduce again on that taking the first value of splitting on '-':
let arr = ['11-3\n12-6', '5-9\n7-2\n18-2', '2-7']
let tot = arr.reduce((a, c) => {
let pairs = c.split('\n')
return a + pairs.reduce((a, c)=> a + Number(c.split('-')[0]), 0)
}, 0)
console.log(tot)
console.log(11 + 12 + 5 + 7+ 18 + 2)
You might need to clean up data or split on whitespace if it's not cleanly one \n per line. But this should be a good start.
You can try this:
let arr = [
[
'11-3',
'12-6'
], [
'5-9',
'7-2',
'18-2'
], [
'2-7'
]
];
let sum = 0;
for (let index=0; index<arr.length; index++) {
let arrayMasterElement = arr[index];
// console.log(arrayMasterElement);
for (let index2=0; index2<arrayMasterElement.length; index2++) {
let arrayElement = arrayMasterElement[index2];
let elementArray = arrayElement.split('-');
let intVal = parseInt(elementArray[0]);
console.log('Int value: ' + intVal);
sum += intVal;
}
if (index == arr.length - 1) {
console.log('Sum: ' + sum);
}
}
I have an application that takes in multiple arrays of data each or variable length. I plan on cycling through and displaying every combination of data for each array I'm given. My first inclination was to have a single number represent the state of each array since I know the number of combinations is the product of the number of elements of each array.
So for example:
A = [0,1,2,3]
B = [0,1,2,3]
C = [0,1]
So 4 x 4 x 2 = 32 combinations I need to represent
I've managed to represent all states by applying modulo and division to a given index using each array.length. My problem is that it doesn't order well (see snippet below). Has anyone solved a similar problem or know how I could change the algorithm to get it in order?
function multiArrayIndex(index, ...args) {
var arrays = args.slice();
var output = [];
for (var i = 0, curIndex = index; i < arrays.length; i++) {
var curArray = arrays[i];
var valueIndex =(curIndex % curArray.length);
output.push(curArray[valueIndex]);
curIndex = Math.ceil(curIndex / curArray.length);
}
return output;
}
demoP = document.getElementById("demo");
for(var i = 32; i>=1; i--){
demoP.innerHTML = demoP.innerHTML + i + " - " + multiArrayIndex(i, [0,1,2,3], [0,1,2,3], [0,1] ) + "<br />";
}
<p id="demo"></p>
Keeping the indices separate would be a nicer approach in my opinion.
Incrementing the indices could work kinda similar to how we added two numbers by hand in elementary school - if an index is too large, set it to zero and increment the next one by one:
var a = [0, 1, 2, 3]
var b = [0, 1, 2, 3]
var c = [0, 1]
var state = {
a: 0,
b: 0,
c: 0
}
function increment() {
state.a++;
if (state.a >= a.length) {
state.b++;
state.a = 0;
}
if (state.b >= b.length) {
state.c++;
state.b = 0;
}
if (state.c >= c.length) {
state.c = 0;
}
console.log(state);
}
console.log(state);
<button onclick='increment()'>Increment</button>
Updating the document based on the state should be trivial from here.
Beginner programmer here. I'm struggling with an assignment that's taking input text, splitting the words into single array items and then listing the total number of each words in an output. The splitting of the input works fine, but I need to check the array for duplicate items and remove that item (need to keep it unique) while also increasing the count on that particular word.
The idea was to make an array consisting of the words alone, and another that keeps track of the count. Glad to receive tips to use a simpler approach as well.
And yes, I know there is several solutions to this problem on SO, but I dont quite understand how to fix this particular code using functions.
function gen()
{
var arr = [];
var counter = [];
var str = document.getElementById("inpTxt").value;
str.toString();
str = str.split(" ");
for(var i = 0; i < str.length; i++)
{
arr.push(str[i]);
counter[i]++; //ignore that this array hasnt been properly declared yet, Im trying to make this equal length of arr with default value 0
//tried nested loop here for making comparison, didnt work
document.getElementById("print").innerHTML += "Total number of the word \"" + arr[i] + "\": " + counter[i] + " <br />";
}
}
If you're using ECMAScript2015(ES6), you can build a Set - which guarantees unicity - from your array :
var inputArray = [1, 1, 2, 3, 2, 4, 5, 5, 4, 1];
console.log(new Set(inputArray)) // displays Set { 1, 2, 3, 4, 5 }
Otherwise, you can loop over the array and check if a particular element follows another occurrence of itself :
var inputArray = [1, 1, 2, 3, 2, 4, 5, 5, 4, 1];
// with ES6 :
var result = inputArray.filter((element, index) => ! inputArray.slice(0, index).includes(element));
// without ES6 :
result=[];
for (var i=0; i<inputArray.length; i++) {
var currentElement = inputArray[i];
var previouslyFound = false;
for (var j=0; j<i && !previouslyFound; j++) {
previouslyFound = inputArray[i] == inputArray[j];
}
if (!previouslyFound) result.push(currentElement);
}
However, since we are looping over the array, it would be as fast to count the occurrences without unicizing the array first :
var inputArray = [1, 1, 2, 3, 2, 4, 5, 5, 4, 1];
// with ES6 :
var result = inputArray.reduce(function(map, element) {
map[element] = map.hasOwnProperty(element) ? map[element] + 1 : 1;
return map;
}, {});
// without ES6 :
var result = {};
for (var i=0; i<inputArray.length; i++) {
var currentElement = inputArray[i];
if (result.hasOwnProperty(currentElement)) {
result[currentElement] = result[currentElement] + 1;
} else {
result[currentElement] = 1;
}
}
Try the indexOf method of arrays to figure out whether you already have the string in array.
function gen()
{
var arr = [];
var counter = [];
var str = document.getElementById("inpTxt").value;
str.toString();
str = str.split(" ");
for(var i=0; i < str.length; i++)
{
if(arr.indexOf(str)==-1){
arr.push(str[i]);
counter[i]++; //ignore that this array hasnt been properly declared yet, Im trying to make this equal length of arr with default value 0
}
//tried nested loop here for making comparison, didnt work
document.getElementById("print").innerHTML += "Total number of the word \"" + arr[i] + "\": " + counter[i] + " <br />";
}
}
PS: please know that there are less expensive methods available out there but i am just trying to help with whatever i can.