Pushing objects back and forth between arrays results in missing objects - javascript

I have several JSON files with fake users.
They look like this:
{"name":"Beau Evans","personalityType":"yellow","skills":"JavaScript"}.
They are all pushed into an array called 'people'.
Now what I wish to do is to sort them all into subgroups into const groups = []; array.
The requirement for the groups is that they all need to share the same personalityType. (blue, yellow, red, or green) and they all need to differ in skills.
So one with HTML, JavaScript, or CSS.
And this of course resulted in some groups being of just 1 user. So I wanted to extract those back into a remainingPeople array, and then add the remainingPeople EVENLY to groups that meet the requirements so maybe 1 yellowCSS, 1 yellowJavaScript, 1 yellowHTML. It didn't matter if it turned out to be maybe 2 yellowHTML.
This is the code that I've written:
Which resulted into 2 problems.
The while loop on the bottom never stopped looping and crashed the site depending on how many JSON files with fake users I had!
And problem 2: Some users got erased out of existence so I ended up with fewer people in the groups' array than I had in the people array.
Why is this?
let homogenousGroups = [];
for (let i = 0; i < Math.floor(people.length / 3); i++) {
homogenousGroups.push([{
group: i
}]);
}
let groupsCreator = () => {
// this is to add people that has the same personality and different skills to the same group
let addPersonSameColor = (group) => {
people.sort(() => Math.random() - 0.5);
for (let j = 0; j < people.length; j++) {
let person = people[j];
let hasPersonality = group.some(groupPerson => groupPerson.personalityType === person.personalityType);
let hasSkills = group.some(groupPerson => groupPerson.skills === person.skills);
if (group.length === 0) {
group.push(person);
people.splice(j, 1);
j--;
} else if (hasPersonality && !hasSkills) {
group.push(person);
people.splice(j, 1);
j--;
}
}
};
// this runs the function above for each person in
for (let x = 0; x < homogenousGroups.length; x++) {
addPersonSameColor(homogenousGroups[x]);
}
// this will remove any object that does not have the name property
for (let x = 0; x < homogenousGroups.length; x++) {
for (let y = 0; y < homogenousGroups[x].length; y++) {
if (!homogenousGroups[x][y].name) {
homogenousGroups[x].splice(y, 1);
y--;
}
}
}
// this is to push any group that has less than 3 people back to the people array
for (let x = 0; x < homogenousGroups.length; x++) {
if (homogenousGroups[x].length <= 2) {
let removed = homogenousGroups[x].splice(0, homogenousGroups[x].length);
people2.push(...removed);
}
for (let x = 0; x < people.length; x++) {
if (people[x].group) {
people.splice(x, 1);
x--;
}
}
}
// this is to remove any empty arrays in my group array
for (let x = 0; x < homogenousGroups.length; x++) {
if (homogenousGroups[x].length === 0) {
homogenousGroups.splice(x, 1);
x--;
}
}
while (people.length > 1) {
for (let i = 0; i < homogenousGroups.length; i++) {
for (let j = 0; j < people.length; j++) {
if (people[j].personalityType === homogenousGroups[i][0].personalityType) {
homogenousGroups[i].push(people[j]);
people.splice(j, 1);
j--;
break;
}
}
}
}
};

Related

using splice inside 2D Array in Javascript

I've created this 2D array, and I'm trying to delete the rows that are having 5 "ones" or more,
I tried it with splice (a.splice(j,1)) but it doesn't work . I think because when using this method it changes the whole quantity of rows and that's affects the for loops.
Is it because I don't use splice correctly or should I use different method ?
Thanks !
a = Array(7).fill(0).map(x => Array(10).fill(0))
for (let i = 0; i < 5; i++) {
a[1][i + 2] = 1;
a[4][i + 2] = 1;
a[5][i + 2] = 1;
}
console.log(a);
let count = 0;
for (let j = 0; j < 7; j++) {
for (let i = 0; i < 10; i++) {
if (a[j][i] == 1) {
count = count + 1;
}
}
if (count > 4) {
console.log("Line" + j);
// a.splice(j,1);
}
count = 0;
// a.splice(j,1);
}
Your splice is correct but you move forward through the array (j is incremented). To do this type of operation you need to move backward through the array (j is decremented) - this way the changing array indices don't intefere with your loop.
See the example below:
a = Array(7).fill(0).map(x => Array(10).fill(0))
for (let i=0; i<5; i++) {
a[1][i+2] = 1;
a[4][i+2] = 1;
a[5][i+2] = 1;
}
console.log("Original array");
console.log(a);
for (let j = a.length - 1; j > 0; j--) {
var count;
for (let i = 0; i < a[j].length; i++) {
if (a[j][i] === 1) {
count += 1
}
}
if (count > 4) {
a.splice(j, 1);
}
count = 0;
}
console.log("Filtered array");
console.log(a);

Code blocks work separately but not together

I'm making a function for my chrome extension. It's supposed to move all tabGroups to the left most position in alphabetical order and then sort the rest of the tabs in alphabetical order aswell.
The problem is when I remove this code block everything works fine, meaning the tabGroups gets moved to the left most position. But when I add it back it stops working. The thing is that the code block works on it's own if I manually move the tabGroups myself. Any help is appreciated!
for (let i = 0; i < titles.length; i++) {
for (let j = 0; j < titles.length; j++) {
if (tabs[i + moveIndex].title == titles[j]) {
chrome.tabs.move(tabs[i + moveIndex].id, { index: (j + moveIndex) });
}
}
}
This is the full function, with tabs being: let tabs = await chrome.tabs.query({ currentWindow: true });
async function titleSort(tabs) {
// Puts groups in current window into an array
let groups = await chrome.tabGroups.query({ windowId: -1 });
console.log(groups);
// Separates titles into a different array
let groupTitles = [];
for (let i = 0; i < groups.length; i++) {
groupTitles.push(groups[i].title);
}
// Sorts the array alphabetically
groupTitles.sort((a, b) => a.localeCompare(b));
console.log(groupTitles);
// Put groups into an array in alphabetical order
let groupsAlph = [];
for (let i = 0; i < groups.length; i++) {
for (let j = 0; j < groupTitles.length; j++) {
if (groupTitles[i] == groups[j].title) {
groupsAlph.push(groups[j]);
}
}
}
console.log(groupsAlph);
chrome.storage.sync.get(["preserveGroupOrder"], (data) => {
if (data.preserveGroupOrder == false) {
// Separates titles into a different array
let titles = [];
for (let i = 0; i < tabs.length; i++) {
titles.push(tabs[i].title);
}
// Sorts the array alphabetically
titles.sort((a, b) => a.localeCompare(b));
// Checks if the titles match and rearranges the tabs accordingly
for (let i = 0; i < tabs.length; i++) {
for (let j = 0; j < titles.length; j++) {
if (tabs[i].title == titles[j]) {
chrome.tabs.move(tabs[i].id, { index: j });
}
}
}
} else if (data.preserveGroupOrder == true) {
let tabsInGroup = [];
// Resets values to 0 in tabsInGroup
for (let i = 0; i < groups.length; i++) {
tabsInGroup[i] = 0;
}
// Gets the amount of tabs in each group
for (let i = 0; i < tabs.length; i++) {
for (let j = 0; j < groups.length; j++) {
if (tabs[i].groupId == groupsAlph[j].id) {
tabsInGroup[j]++;
}
}
}
console.log(tabsInGroup);
// Moves groups to the left most positions
let moveIndex = 0;
for (let i = 0; i < groupsAlph.length; i++) {
chrome.tabGroups.move(groupsAlph[i].id, { index: moveIndex });
moveIndex += tabsInGroup[i];
}
console.log(moveIndex);
// Separates titles into a different array
let titles = [];
let tabsLength = tabs.length - moveIndex;
for (let i = 0; i < tabsLength; i++) {
titles.push(tabs[i + moveIndex].title);
}
// Sorts the array alphabetically
titles.sort((a, b) => a.localeCompare(b));
console.log(titles);
// TODO: Sort the rest of the tabs (works separately)
// Checks if the titles match and rearranges the tabs accordingly
for (let i = 0; i < titles.length; i++) {
for (let j = 0; j < titles.length; j++) {
if (tabs[i + moveIndex].title == titles[j]) {
chrome.tabs.move(tabs[i + moveIndex].id, { index: (j + moveIndex) });
}
}
}
}
});
}
I'm fairly confident that the issue is that you're not requerying tabs after you move tab groups:
chrome.tabGroups.move(groupsAlph[i].id, { index: moveIndex });
If you're only creating the tabs index once, then if tabs 6 - 8 are part of a group, and the group gets moved to index spots 0-2 by that line, your tabs variable does not know that unless you requery. So when you start resorting tabs 3 through 8, you're including tabs you don't want to and excluding tabs that you do. If for some reason you don't want to requery, you could keep track of the index numbers where you find tabs and have your title builder start at zero and skip the tabs. I.e., instead of ->
for (let i = 0; i < tabsLength; i++) {
titles.push(tabs[i + moveIndex].title); ...
Something like ->
for (let i = 0; i < tabs.length; i++) {
if (isNotGroupMember[i]) {
titles.push(tabs[i].title); ...
You would need to readjust some other pieces, but there's a good chance that will be the case regardless.
If that's not the issue, it's not clear from your code and I have a second hypothesis, but I'd try that first.
Also, it's not your question, but you may be interested in sorting arrays of objects by a key, rather than separating out the titles, sorting those, and then match sorting them back into place. See an example at w3schools. Although maybe there's a good reason to build your own sort.

How to make a loop that go up and down at the same time?

i was wandering how to make a loop that go up and down at the same time.
For example, here is the normal loop:
for(let i = 0; i < number.length; i++){}
for(let i = 0; i < number.length; i--){}
How can i simplify this loop?
You can have as many indexes as you want in a for loop:
a = [1,2,3,4,5,6,7]
for (let i = 0, k = a.length - 1; i < a.length && k >= 0; i++, k--) {
console.log(i, k)
}
or, you can compute the second index from the first
a = [1,2,3,4,5,6,7]
for (let i = 0; i < a.length; i++) {
let k = a.length - 1 - i
console.log(i, k)
}
If you want to do that in the modern way, without any indexes at all, this would require some runtime support:
function* iter(a) {
yield* a;
}
function* reversed(a) {
yield* [...a].reverse();
}
function* zip(...args) {
let iters = args.map(iter);
while (1) {
let rs = iters.map(it => it.next());
if (rs.some(r => r.done))
break;
yield rs.map(r => r.value);
}
}
//
a = 'abcdef'
// just like in python!
for (let [x, y] of zip(a, reversed(a)))
console.log(x, y)
You could just embed 2 loops. Such as:
for(let i = 0; i < number.length; i++){ // i going "up"
for(let j = number.length; j > 0; j--){} // j going "down"
}
If you want to get the values from first to the last value and vise versa at the same time you don't have to use double loops. Instead just use the i and arrays length. Here's an example.
var length = number.length - 1
for(let i = 0; i < number.length; i++){
console.log(number[i])
console.log(number[length-i])
}

How to improve the performance of 'for loop' to integrate some objects in JS

I have three for loop as below to integrate their objects.
The problem is the length of 'cars' array is 20,000.
So it should runs every 20,000 times for finding same id between company.user and cars.
But the id of cars is unique.
Can I reduce this repeat number in JS?
I want to reduce the taking time.
Thank you for reading it.
p.s. I uploaded same question adding the concrete logic inside of for loop.
for (let i = 0; i < company.length; i += 1) {
for (let j = 0; j < company[i].user.length; j += 1) {
for (let k = 0; k < cars.length; k += 1) {
if (company[i].user[j].id === cars[k].id) {
company[i].user[j] = {
...company[i].user[j],
...cars[k]
}
}
}
}
}
If there is only 1 match then use break after you found that item. Imagine you find that item at index 1 for example, then the loop would still continue and do 19998 loops. Because of the information that you know there is only 1 possible match you can break it there.
if (company[i].user[j].id === cars[k].id) {
company[i].user[j] = {
...company[i].user[j],
...cars[k]
}
break;
}
for (let i = 0, leni = company.length;; i < leni ; i += 1) {
for (let j = 0, lenj = company[i].user.length; j < lenj; j += 1) {
for (let k = 0, lenk = cars.length; k < lenk; k += 1) {
if (company[i].user[j].id === cars[k].id) {
company[i].user[j] = {
...company[i].user[j],
...cars[k]
}
break; // match only the first one, then stop searching for cars
}
}
}
}
Answer based on test results from https://jsperf.com/caching-array-length/4
Spread left in base on
https://thecodebarbarian.com/object-assign-vs-object-spread.html
this will optimize your code a little more, but ziga1337 is right, the only effective way is to sort your two objects
// company: [ { user: [ { id: '?1'
// cars: [ { id: '?2'
for (let iCompagny of compagny) {
for (let iUser of iCompagny.user) {
let fCar = cars.find(xCar.id===iUser.id)
if (fCar) Object.assign(iUser, fCar)
}
}
in case there is always a car.id unique to each user.id:
let indexCars = cars.reduce((a,c)=>{ a[c.id]=c; return a },{})
compagny.forEach(iCompagny=>{
iCompagny.user.forEach(iUser=>{ Object.assign(iUser, indexCars[iUser.id]) })
})

How do I change a specific value found when looping a 2d array?

Trying to replace values of an array in an array.
The array only has values 1 or 0, it is a grid.
Code is looking for a 1 and change that to 0 and also change the same column value of the row below to 1.
I belive the problem is im making the if statement invalid with the changes im trying to make. Resulting in error message.
function gravity() {
for (var i = 0; i < rows; i++) {
for (var j = 0; j < cols; j++) {
if (grid[i][j] === 1){
grid[i][j] = 0;
grid[i+1][j] = 1;
}
}
}
}
The problem is that when your loop is in the last row it will try to set i+1 to 1, but since i is already the last index i+1 is out of bounds.
To fix this you can simply add an if
You also have another bug. Since you interate from top to bottom you move any 1's down to the next row, then you go through the next row and find the exact same 1's that you have just moved down and move them down again. This repeats until all 1's are gone, all in a single call to gravity(). To fix this you have to interate through the rows from bottom to top.
var grid = [
[1,0,0,0],
[0,0,1,0],
[0,0,0,0],
[0,1,0,0]
]
var cols = 4;
var rows = 4;
function gravity() {
for (var i = rows - 1; i >= 0; i--) {
for (var j = 0; j < cols; j++) {
if (grid[i][j] === 1){
grid[i][j] = 0;
if(i+1 < rows) {
grid[i+1][j] = 1;
}
}
}
}
}
var iterations = 0;
var intervalId = setInterval(() => {
gravity();
for(var row of grid) {
console.log(row.join(','))
}
console.log("");
iterations++;
if(iterations == 4) {
clearInterval(intervalId);
}
}, 400)

Categories

Resources