I have an array that whenever I fire a function called X I want to get random element from that array. The function will be called many times and every time I call that function I want to get element I didn't get before. I also need a reference to all elements so I can't be just removing from array Here are my 2 solutions I came up with:
Make a function that gets a random index number excluding some numbers. Problem with function like this is that it basically works that whenever the number is equal to the excluded it just generates again until it gets the right one. So when array has like a 1000 elements but only like 10 are left it will be generating forever.
Make a second array both would be the same at beginning. however I only remove from the second, and I can get random index from the second. Problem is whenever I remove that element using splice() from second array he is actually removed from both arrays. Is there a way to remove just from 1 array?
Am I just making some stupid mistakes and there is some simple solution that I am missing?
This is a perfect use case for a generator function. It will return undefined when you've exhausted the shuffled input array.
const input = [1,2,3]
function* shuffle(arr) {
arr = [...arr] // make a shallow copy, to avoid mutating the original
while(arr.length) yield arr.splice(Math.random()*arr.length|0, 1)[0]
}
let generator = shuffle(input);
console.log(generator.next().value)
console.log(generator.next().value)
console.log(generator.next().value)
console.log(generator.next().value)
You could generate a second array of indexes, shuffle it, and pop an index from it.
Once the index array is empty, refill it.
Something like
array = ['my', 'items', 'to', 'select']
// Fisher-Yates shuffle
function shuffle(ar) {
for(let i = ar.length - 1; i >= 1; i--) {
let temp = Math.floor(Math.random() * (i + 1)); // select an item to swap with
[ar[temp], ar[i]] = [ar[i], ar[temp]]; // do the swap
}
}
let indices = [];
function nextItem() {
if(indices.length == 0) {
// generate the array of indexes
indices = array.map( (item, index) => index );
shuffle(indices);
}
return array[indices.pop()];
}
// Call it a few times
for(let i = 0; i < 10; i++) {
console.log( nextItem() );
}
If you were concerned at all about performance, instead of popping from indices and regenerating a new array, you could instead have a "current index" that walks through the array, and when it gets to the end reshuffle.
For solution 2, you need your second array to be copy of the original, not a reference to the original. Try this:
const originalArray = ['one', 'two', 'three']
let copyArray = [...originalArray]
I have two sets of arrays, one containing date values in months(in no order) the other containing corresponding month values as such;
array1=['jan','mar','dec','jan','sep','nov','mar']
array2=[3,5,5,4,5,8,2]
as seen, each month can appear more than once.
id like to cluster/sort this data to have 2 arrays that show month and corresponding total values, in essence, get all the values that correspond to january, sum them and output them to another array as well as a forth array containing months, without repeats. something like
array3=['jan','mar','sep',nov','dec']
array4=[7,7,5,5,8] //totals
you can use a dictionary to keep track of identical months. If months repeated it will add to the value in dictionary.
array1=['jan','mar','dec','jan','sep','nov','mar']
array2=[3,5,5,4,5,8,2]
res = {}
for(let i=0;i<array1.length;i++){
if(array1[i] in res){
res[array1[i]]+= array2[i]
} else {
res[array1[i]] = array2[i]
}
}
array3 = []
array4 = []
for(let i in res){
array3.push(i)
array4.push(res[i])
}
You could use new Map() here and then just map to pick necessary values.
array1=['jan','mar','dec','jan','sep','nov','mar']
array2=[3,5,5,4,5,8,2]
const months = new Map();
array1.forEach((month, index) => {
months.set(month, (months.get(month) || 0) + array2[index]);
});
const array3 = Array.from(months, ([month]) => month);
const array4 = Array.from(months, ([month, summ]) => summ);
console.log(array3);
console.log(array4);
This approach can also sort based on month number.
let array1=['jan','mar','dec','jan','sep','nov','mar']
let array2=[3,5,5,4,5,8,2]
//this is for saving the index and final sorting after monthwise summing up values
monthsObj = {};
['jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec'].forEach((name,index) => {monthsObj[name]=index})
function getSum(a1, a2){
let obj = {};
for(let i=0;i<a1.length;i++){
//if the month is not present in the obj
if(obj[a1[i]] === undefined) obj[a1[i]] = a2[i];
else obj[a1[i]] += a2[i]; //otherwise add to the previous month value
}
//sort based on month numbers
let sorted = [...Object.entries(obj)].sort(function(a, b) {
return monthsObj[a[0]]-monthsObj[b[0]];
});
let final1 = [], final2=[];
for(let i=0;i<sorted.length;i++){
final1.push(sorted[i][0]);
final2.push(sorted[i][1]);
}
console.log(final1, final2);
}
getSum(array1, array2);
The Set object lets you store unique values of any type, whether primitive values or object references. With that, you can omit duplicate values in your array. (you can read this resource for more information about Set.)
The Object.values() method returns an array of a given object's own enumerable property values, in the same order as that provided by a for...in loop. (The only difference is that a for...in loop enumerates properties in the prototype chain as well.) for more details, you can read this
array1=['jan','mar','dec','jan','sep','nov','mar']
array2=[3,5,5,4,5,8,2]
const months = {};
array1.forEach((month, index) => {
months[month]=(months[month] || 0) + array2[index];
});
const array3 = Array.from(new Set(array1));
const array4 = Object.values(months) ;
console.log(array3);
console.log(array4);
Hello i would like to create something for sort args in the list by how many times they are in the list
all arguments are separated with one ;
let list = "abcd1; abcd4; abcd4; abcd9; abcd2; abcd5"
the list can be 5 args long like 100 or 243.
i think it can work with two for loops one to see if the i element is duplicated and compare the array[i] with the array[j] and you could use a temporary array to create the object then later reassign to the main array.
but don't know how to do it.
Your list
let list = "abcd1; abcd4; abcd4; abcd9; abcd2; abcd5"
Create a new list by splitting the string at ';'
let newList = list.split(';')
// newList = ["abcd1", " abcd4", " abcd4", " abcd9", " abcd2", " abcd5"]
Declare an empty object and iterate through all elements of new list and add them as keys to the object. Set the value as 1 if the key is not present in the object, else add 1 to the value if key is present.
let obj = {}
for (let i of newList) {
let newI = i.trim() // trim() to remove spaces or new line characters
// check if newI is already present in the object, i.e. we've seen it before
// if that's the case then it must have a value so increment that value by 1
if (newI in obj) {
obj[newI] += 1
}
// if newI is not present in the object then we're seeing it for the first time.
// so set its value as 1
else {
obj[newI] = 1
}
}
// obj = {abcd1: 1, abcd4: 2, abcd9: 1, abcd2: 1, abcd5: 1}
Get the keys of the object in an array and finally sort that array while sending the value in the object ``obj``` as comparison parameter. As we want to sort by how many times that value appears in the string.
let arr = Object.keys(obj)
// arr = ["abcd1", "abcd4", "abcd9", "abcd2", "abcd5"]
arr.sort((a, b) => obj[a] - obj[b])
// arr = ["abcd1", "abcd9", "abcd2", "abcd5", "abcd4"]
Sorted from least number of appearances in string to maximum number of appearances
I have an array of values:
let myArray = [ 'Ifmanwas',
'meanttos',
'tayonthe',
'groundgo',
'dwouldha',
'vegivenu',
'sroots' ]
I want to print out a new value for each item in the array so that the first item is a collection of all the characters at the zero index, the second is a collection of all the characters at the 1 index position, ect...
So for instance, the output of the first array would be "Imtgdvs" (all the letters at ("0"), the second would be "fearwer" (all the letters at index "1") ect...
I am very lost on how to do this and have tried multiple different ways, any help is appreciated.
For this simple attempt I have created an array of all the letters for the first instance:
function convertToCode(box) {
let arr = [];
for (i = 0; i < box.length; i++) {
let counter = i;
let index = box[counter];
let letter = index.charAt(0);
arr.push(letter);
}
console.log(arr);
}
convertToCode(myArray)
Thanks
The main issue in your example is this: index.charAt(0);. This will always get the first character, whereas you need a nested loop.
You could use Array.map() in combination with Array.reduce(), like so:
let myArray = ['Ifmanwas','meanttos','tayonthe','groundgo','dwouldha','vegivenu','sroots'];
const result = Array.from(myArray[0]) //Create an array as long as our first string
.map((l,idx) => //Update each item in that array...
myArray.reduce((out,str) => str[idx] ? out+str[idx] : out, "") //to be a combination of all letters at index [idx] from original array
);
console.log(result);
Note that this uses the first string in the array to decide how many strings to make, as opposed to the longest string.
I've got a list of calls with phone numbers and numbers of times that I called these numbers.
Every time I call I do something like this:
const pos = '.' + this.number; // avoid arrays large as a mobile number but keeping the number for indexing
if (typeof(this.list[pos]) === 'undefined') {
this.list[pos] = 1;
} else {
this.list[pos] = this.list[pos] + 1;
}
So I can get how many times did I call that number doing easily something like this.list[number].
The problem comes when I want to iterate this array:
<div *ngFor="let calls of callsListProvider.list">{{calls}}</div>
The length of the array is always 0 because I didn't push the content.
I don't want to use objects. Is this possible to iterate and also get the number (the index) as well?
If this.list is an Array having property names set to values other than indexes you can substitute using for..in loop for for..of loop.
let arr = [];
arr["a"] = 1;
arr["b"] = 2;
for (let prop of arr) {
console.log("for..of loop", prop);
}
for (let prop in arr) {
console.log("for..in loop", prop);
}