Related
I'm trying to organize an array I have according to certain conditions that must be met.
I have 3 kinds of arrays:
Array of people
var array1 = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]
Array of dates
var array2 = ["date1","date2","date3","date4"]
For each value in array2, I have corresponding separate arrays (or 2D arrays, don't know what's best to be honest)
var date1Group1 = [1,6,7,8]
var date1Group2 = [4,5,9]
var date1Group3 = [6,17,15,3,11]
OR
var date1Groups = [[1,6,7,8],[4,5,9],[6,17,15,3,11]]
Each date has their own corresponding group arrays
var date2Groups = [...]
...
var date4Groups = [...]
What I need to do is to distribute proportionately the values of array1 into a new array corresponding to having it split by array2.length. In this particular case since:
array1.length = 18
array2.length = 4
I can have for example 1 2D array of 2 sub-arrays of 5 values and 2 sub-arrays of 4 values, OR 4 separate arrays for each group:
var arrayResultDate = [[v1,v2,v3,v4,v5],[v1,v2,v3,v4,v5],[v1,v2,v3,v4],[v1,v2,v3,v4]]
OR
var arrayResultDate1 = [v1,v2,v3,v4,v5]
var arrayResultDate2 = [v1,v2,v3,v4,v5]
var arrayResultDate3 = [v1,v2,v3,v4]
var arrayResultDate4 = [v1,v2,v3,v4]
In order to distribute them, I need to check that the values asigned to each of these new arrays, are not repeated in a same group of it's corresponding date. For example:
//This is valid be because no value is repeated in any of the groups for date1
arrayResultDate1 = [2,4,7,14,18]
//This is NOT VALID because values 6 and 8 are in date1Group1 / date1Groups[0]
arrayResultDate1 = [3,6,8,18,12]
What I wanted to do was first asigning from array1[0] to array1[3], to arrayResultDate1 to arrayResultDate4 (1 each)
arrayResultDate1.push(array1[0])
arrayResultDate2.push(array1[1])
arrayResultDate3.push(array1[2])
arrayResultDate4.push(array1[3])
OR
arrayResultDate[0].push(array1[0])
arrayResultDate[1].push(array1[1])
arrayResultDate[2].push(array1[2])
arrayResultDate[3].push(array1[3])
Then use loops to go through the rest of the values in array1, and check if the criteria is met in each resulting array. Asing to the array if conditions are met or go for the next one if it doesn't.
Conditions:
If trying to asign array1[x] to arrayResultDate1, check if value array1[x] AND values already in arrayResultDate1, are at the same time in any of the groups for date1:
date1Group1 = [1,6,7,8]
date1Group2 = [4,5,9]
date1Group3 = [6,17,15,3,11]
If said values ARE NOT at the same time in any of the groups, then
arrayResultDate1.push(array1[x])
If the values ARE in at least one of the groups, then continue with the next resulting array and check with it's corresponding groups (in this case it would be arrayResultDate2 so date2Group1, date2Group2, etc.)
I wasn't able to organize the code properly due to the loops inside other loops that I assume are needed. I hope this is a bit more clear. Please let me know if it's still not.
Use Array.filter() and Array.sort(), like this:
function test() {
const people = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,];
const criteria = [
{ label: 'date1', mutuallyExclusive: [[1, 6, 7, 8,], [4, 5, 9,], [6, 17, 15, 3, 11,],], },
{ label: 'date2', mutuallyExclusive: [[1, 6,],], },
{ label: 'date3', mutuallyExclusive: [[1, 7,],], },
{ label: 'date4', mutuallyExclusive: [[1, 8,],], },
];
const assignments = distributeObjectsToGroups(people, criteria);
console.log(assignments);
}
/**
* Distributes objects to groups observing multiple mutual exclusivity criteria.
*
* Processes each object in turn in the order they appear in the objects array.
* Attempts to make result groups approximately equal size by placing each object
* in the currently smallest group.
* Puts objects that do not fit in any group in an 'unassigned' group.
*
* #param {Object[]} objects The objects to place into groups, as in [1, 2, 3, 4,].
* #param {Object[]} groups An array of group labels and mutual exclusivity criteria.
* Each criteria is a 2D array that lists objects that should be
* mutually exclusive and not appear in the same result group.
* [
* { label: 'date1', mutuallyExclusive: [[1, 2, 3,], [2, 4,]], },
* { label: 'date2', mutuallyExclusive: [[2, 3,],], },
* ]
* #return {Object} The group labels and objects placed in each group.
* { date1: [1, 4,], date2: [2,], unassigned: [3,], }
*/
function distributeObjectsToGroups(objects, groups) {
// version 1.1, written by --Hyde, 3 November 2022
// - see https://stackoverflow.com/a/74294212/13045193
const result = { unassigned: [], };
groups.forEach(group => result[group.label] = []);
objects.forEach(object => {
const suitable = groups
.filter(group =>
!group.mutuallyExclusive.some(exclude =>
exclude.includes(object) &&
result[group.label].some(object2 => exclude.includes(object2)))
)
.sort((a, b) => result[a.label].length - result[b.label].length);
if (suitable.length) {
result[suitable[0].label].push(object);
return;
}
result.unassigned.push(object);
});
return result;
}
A test run logs this:
{
date1: [1, 5, 10, 13, 17],
date2: [2, 6, 9, 14, 18],
date3: [3, 7, 11, 15],
date4: [4, 8, 12, 16],
unassigned: [],
}
See Apps Script at Stack Overflow.
I built a program that check if there are two common numbers in two different arrays, and then log those numbers. I was able to do that using a simple for loop that goes trough each element of the first array and check if there is an equal element in the second array. Each of the same element in the arrays are stored in a third array called "commonNumbers" which I logged at the end of the program.
const firstNumbers = [12, 45, 6, 78]
const secondNumbers = [6, 7, 12, 45]
let commonNumbers = []
for (let i = 0; i < firstNumbers.length; i++) {
for (let j = 0; j < secondNumbers.length; j++) {
if (firstNumbers[i] === secondNumbers[j]) {
commonNumbers += secondNumbers[j]
}
} }
console.log(commonNumbers)
The result for this example is the seguent:
12456
[Finished in 0.2s]
My question is about the result. I can see that the program actually worked and logged the same element in the arrays (12, 45, 6), but I can't figure out why "commonNumbers" stored the result in such a way that there are no spaces between the numbers.
I would like to clearly see each number.
For example if I call the first element of "commonNumbers" (of index 0):
commonNumbers[0] the result I will get is not going to be "12" as expected, but "1".
Same thing happen if I say: commonNumbers[2] the result is going to be "4", not "6".
Apparently "commonNumbers" array stored the element in a different way I was expecting. How can I solve this, using this "storing" method?
This is because +=, on your array, implicitly convert it to a string, as you can see in the example below, where a Number is summed to an Array.
console.log(typeof([] + 1));
Just use the comfortable .push (read more about push here) method of arrays in order to add the element:
const firstNumbers = [12, 45, 6, 78]
const secondNumbers = [6, 7, 12, 45]
let commonNumbers = []
for (let i = 0; i < firstNumbers.length; i++) {
for (let j = 0; j < secondNumbers.length; j++) {
if (firstNumbers[i] === secondNumbers[j]) {
commonNumbers.push(secondNumbers[j]);
}
} }
console.log(commonNumbers)
As a (final) side note, there are several other ways to accomplish your task, the cleverest you can probably go with is filter. You may also would take care of eventual duplicates, since if your input array has two identical numbers the commonsNumber result will contain both, which might be unintended.
The "definitive" clever solution that tries to also take care of duplicates and to loop the shorter array would be something like this:
// Inputs with duplicates, and longer array on second case.
const firstNumbers = [12, 45, 6, 78, 12, 12, 6, 45];
const secondNumbers = [6, 7, 12, 45, 45, 45, 12, 6, 99, 19, 5912, 9419, 1, 4, 8, 6, 52, 45];
// Performance: look for duplicates starting from the shortest array. Also, make a set to remove duplicate items.
const [shortestArray, longestArray] = firstNumbers.length < secondNumbers.length ? [firstNumbers, secondNumbers] : [secondNumbers, firstNumbers];
// Remove duplicates.
const dedupes = [...new Set(shortestArray)];
// Find commomn items using filter.
const commons = dedupes.filter(i => longestArray.indexOf(i) > -1);
console.log('commons is', commons);
Don't get me wrong, the solution is fine, just wanted to add "something" to the boilerplate, to take care of eventual additional scenarios.
const firstNumbers = [12, 45, 6, 78]
const secondNumbers = [6, 7, 12, 45]
let commonNumbers = []
for (let i = 0; i < firstNumbers.length; i++) {
for (let j = 0; j < secondNumbers.length; j++) {
if (firstNumbers[i] === secondNumbers[j]) {
commonNumbers.push(secondNumbers[j])
}
} }
The push method appends values to an array.
You seem to be looking for array.prototype.push (mdn). E.g.:
const firstNumbers = [12, 45, 6, 78]
const secondNumbers = [6, 7, 12, 45]
let commonNumbers = []
for (let i = 0; i < firstNumbers.length; i++)
for (let j = 0; j < secondNumbers.length; j++)
if (firstNumbers[i] === secondNumbers[j])
commonNumbers.push(secondNumbers[j]);
console.log(commonNumbers); // as an array
console.log(commonNumbers.join(', '));
why "commonNumbers" stored the result in such a way that there are no spaces between the numbers.
The + operator will try to cast its operands to compatible types. In this case, that is a string, where empty arrays [] are cast to empty strings '', and numbers 3 are cast to the corresponding string '3'. E.g. [] + 3 is the string '3'.
console.log([], typeof []);
console.log(3, typeof 3);
console.log([] + 3, typeof ([] + 3));
This question already has answers here:
Why does changing an Array in JavaScript affect copies of the array?
(12 answers)
Closed 4 years ago.
This code seems straightforward enough
let arr = [1,2,3,4,5,6]
let store = [];
for(i = 0; i < arr.length; i++){
console.log(arr)
store.push(arr)
arr.push(arr.shift())
}
console.log('store', JSON.stringify(store))
I'm expecting it to return
[[1,2,3,4,5,6],[2,3,4,5,6,1],[3,4,5,6,1,2],[4,5,6,1,2,3],[5,6,1,2,3,4],[6,1,2,3,4,5]]
But when the loop is complete, it shows
[[1,2,3,4,5,6],[1,2,3,4,5,6],[1,2,3,4,5,6],[1,2,3,4,5,6],[1,2,3,4,5,6],[1,2,3,4,5,6]]
When printing the values in the console, they appear correct, but when the store variable is logged, they are all reordered.
[1, 2, 3, 4, 5, 6]
[2, 3, 4, 5, 6, 1]
[3, 4, 5, 6, 1, 2]
[4, 5, 6, 1, 2, 3]
[5, 6, 1, 2, 3, 4]
[6, 1, 2, 3, 4, 5]
Why is this occurring?
There is a similar question here, but it doesn't really provide an answer for my case.
Creating a pair of arrays from an array resulting in circular array
Just make sure you are inserting not the same reference to your array:
let arr = [1,2,3,4,5,6]
let store = [];
for(i = 0; i < arr.length; i++){
store.push(Array.from(arr)) // <-- Make sure not the same ref
arr.push(arr.shift())
}
console.log('store', JSON.stringify(store))
store contains the same instance of arr 6 times. You modify it and print it every time, then add the same object to store, then modify it again.
To get your desired behaviour you need to add a new instance every time e.g. by cloning it when you add it.
You could push a copy which does not keep the same object reference.
let arr = [1, 2, 3, 4, 5, 6]
let store = [];
for (i = 0; i < arr.length; i++) {
store.push(arr.slice()) // just take a copy
arr.push(arr.shift())
}
console.log(store.map(a => a.join(' ')))
Alternate approach leaving original array untouched and using splice() to remove beginning elements and concat() to add to the end
let arr = [1,2,3,4,5,6];
let store = arr.map((_,i)=> {
let a = arr.slice();
return i ? a.concat(a.splice(0,i)) : a;
})
console.log(JSON.stringify(store))
On every loop, you are pushing the reference of the array to store
Example:
Loop - reference of arr - 0x112, then store[ i ] = reference to 0x112
At end:
arr - refer to 0x112 - value = [1, 2, 3, 4, 5, 6]
store[ ] = [ref(0x112), ref(0x112), ref(0x112), ref(0x112), ref(0x112), ref(0x112)]
Use this:
let arr = [1,2,3,4,5,6]
let store = [];
for(i = 0; i < arr.length; i++){
console.log(arr)
let newArr = arr.slice();
store.push(newArr)
arr.push(arr.shift())
}
console.log('store', JSON.stringify(store))
Making a project which involves generating random numbers, which is easy enough with Math.random(). A new number will be generated every n seconds, and i want to be able to display the 5 most recent numbers.
The best I could come up with is creating an array with all the generated numbers, pushing new ones, and then getting the 5 most recent indexes.
Is there a better way to only store only the 5 most recent, as there will be thousands of these numbers being generated?
The best I could come up with is creating an array with all the
generated numbers, pushing new ones, and then getting the 5 most
recent indexes.
Rather than just pushing, do shift and push
var randomArr = [];
function addRandom()
{
//var newNum = randomNumber();
if ( randomArr.length >= 5 )
{
randomArr.shift();
}
randomArr.push( newNum );
}
Now you don't need to do a splice, just take the randomArr array as is.
try this:
var array = [Math.random(), Math.random(), Math.random(), Math.random(), Math.random()];
function addToArray() {
array.push(Math.random());
array.shift();
}
function getLast5() {
return array;
}
Logic Maybe like below just do it with random numbers I am showing you with fixed numbers to make it more clear what is happening behind the scene
var randomNumbers= [];
randomNumbers.push(2); // randomNumbers is now [2]
randomNumbers.push(5); // randomNumbers is now [2, 5]
randomNumbers.push(7); // randomNumbers is now [2, 5, 7]
randomNumbers.push(9); // randomNumbers is now [2, 5, 7, 9]
randomNumbers.push(1); // randomNumbers is now [2, 5, 7, 9, 1]
randomNumbers.shift(); // randomNumbers is now [5, 7, 9, 1]
randomNumbers.push(10); // randomNumbers is now [5, 7, 9, 1, 10]
With ECMAScript2016, you can do:
var arr = [1, 2, 3];
var newNumber = 4;
arr = [ ...arr.slice(1), newNumber ];
console.log(arr);
How to remove row in two dimensional array in JavaScript with row number. If I want to delete all elements in row number 4 then how can do it??
Here's an example of how to remove a row by using splice:
var array = [];
var count = 0;
for (var row=0; row<4; row++) {
array[row] = [];
for (var col=0; col<5; col++) {
array[row][col] = count++;
}
}
console.log(array);
[ [ 0, 1, 2, 3, 4 ],
[ 5, 6, 7, 8, 9 ],
[ 10, 11, 12, 13, 14 ],
[ 15, 16, 17, 18, 19 ] ]
function deleteRow(arr, row) {
arr = arr.slice(0); // make copy
arr.splice(row - 1, 1);
return arr;
}
console.log(deleteRow(array, 4));
[ [ 0, 1, 2, 3, 4 ],
[ 5, 6, 7, 8, 9 ],
[ 10, 11, 12, 13, 14 ] ]
Lets say you have an array 'arr' then you can remove full row by arr.splice(3,1);
I realize this question is old, but it is one of the first results when searching for how to remove from a 2d (multidimensional) array in JS.
Here is what I used to delete the inner array based on a key of the inner array. It should continue to work if there were multiple instances of the same key. In this example, I am searching for, and removing the array with the key of 18.
Sorry about the formatting - it gets the point across.
var items = [
["19", 1],
["18", 2],
["20", 3]
];
//console.log(items);
document.getElementById("a").innerHTML = items;
for (var i = 0; i < items.length; i++) {
if (items[i][0] == "18") {
items.splice(i, 1);
}
}
//console.log(items);
document.getElementById("b").innerHTML = items;
<p>Before</p>
<div id='a'></div>
<p>After</p>
<div id='b'></div>
Just call the splice(4, 1) method, when 4 is row number and 1 is number of rows to remove -
twoDimensionalArray.splice(4, 1); // remove 4th row
Also shift() and pop() are very handy methods which remove first and last rows accordingly -
twoDimensionalArray.shift(); // to remove first row
twoDimensionalArray.pop(); // to remove last row
Here you have a visual example of a bidimensional array with row deletion button (delete by ID) + jQuery preview of the table.
I hope it can be usefull!
JS DELETE ROW from Bidimensional ARRAY + Show on jQuery Cart Table https://jsbin.com/xeqixi/edit?html,js,output
delete array[index];
array.length--;
In your case give index as 4 and execute the above statement and you need to manually reduce the length of array.