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.
Related
So... I'm making a page that has notifications, a mark as read button and a mark all as read button, when i try to activate the mark all as read using my loop
let markAllAsRead = () => {
let buttons = document.getElementsByClassName("markAsRead");
let notifications = document.getElementsByClassName("notification");
let newValue = Number(counter.innerText) - 7;
if (newValue < 0) {
newValue = 0;
}
console.log(buttons);
counter.innerText = newValue;
for (let i = 0; i < notifications.length; i++) {
notifications[i].classList.remove("new");
}
for (let i = 0; i < buttons.length; i++) {
buttons[i].remove(buttons[i]);
}
};
it only will eliminate one element yes and other no like so:
live test of the function
I'm back just to update this one, the problem it self was
for (let i = 0; i < buttons.length; i++) {
buttons[i].remove(buttons[i]);
}
instead of make it look for a "default loop" I made "i" be equal to the HTMLCollection lenght, then i>= 0; --i
for (let i = buttons.length - 1; i >= 0; --i) {
buttons[i].remove();
}
making it, the function works as it should removing all the buttons of mark as read.
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;
}
}
}
}
};
The code below is not giving me the expected result.
It's to compare rows from two ranges and, although the second range's last row equals the one from the first range, it gives me false as the result.
var entryValuesCom = sheet.getRange(7, 1, LastRowSource, 9).getValues();
var dbDataCom = dbSheet.getRange(2, 1, dbSheet.getLastRow(), 9).getValues();
var entryVlArray = new Array();
var dbArray = new Array();
for (var r = 0; r < entryValuesCom.length; r++) {
if (entryValuesCom[r][0] != '' && entryValuesCom[r][5] != 'Daily Ledger Bal') {
entryVlArray.push(entryValuesCom[r]);
}
}
for (var a = 0; a < dbDataCom.length; a++) {
if (dbDataCom[a][1] != '' && dbDataCom[a][8] == bank) {
dbArray.push(dbDataCom[a]);
}
}
var duplicate = false;
loop1:
for (var x = 0; x < entryVlArray.length; x++) {
loop2:
for (var j = 0; j < dbArray.length; j++) {
if (JSON.stringify(entryVlArray) == JSON.stringify(dbArray)) {
duplicate = true;
break loop1;
}
}
}
Here's a snapshot of how the array is coming:
I've tried it using .join(), but still...
This is for thousands of rows, so is this going to do well performance wise?
I believe your goal as follows.
You want to compare the arrays of entryVlArray and dbArray using Google Apps Script.
When the duplicated rows are existing between entryVlArray and dbArray, you want to output duplicate = true.
Modification points:
When your script is modified, at if (JSON.stringify(entryVlArray) == JSON.stringify(dbArray)) {, all 2 dimensional arrays are compared. I think that this might be the reason of your issue. From your script, I think that it is required to compare each element in the 2 dimensional array.
When above points are reflected to your script, it becomes as follows.
Modified script:
From:
var duplicate = false;
loop1:
for (var x = 0; x < entryVlArray.length; x++) {
loop2:
for (var j = 0; j < dbArray.length; j++) {
if (JSON.stringify(entryVlArray) == JSON.stringify(dbArray)) {
duplicate = true;
break loop1;
}
}
}
To:
var duplicate = false;
for (var x = 0; x < entryVlArray.length; x++) {
for (var j = 0; j < dbArray.length; j++) {
if (JSON.stringify(entryVlArray[x]) == JSON.stringify(dbArray[j])) {
duplicate = true;
break;
}
}
}
console.log(duplicate)
By this modification, when each element (1 dimensional array) in the 2 dimensional array is the same, duplicate becomes true.
Note:
As other method, when an object for searching each row value is prepared, I think that the process cost might be able to be reduced a little. In this case, the script is as follows. Please modify as follows.
From:
var duplicate = false;
loop1:
for (var x = 0; x < entryVlArray.length; x++) {
loop2:
for (var j = 0; j < dbArray.length; j++) {
if (JSON.stringify(entryVlArray) == JSON.stringify(dbArray)) {
duplicate = true;
break loop1;
}
}
}
To:
var obj = entryVlArray.reduce((o, e) => Object.assign(o, {[JSON.stringify(e)]: true}), {});
var duplicate = dbArray.some(e => obj[JSON.stringify(e)]);
References:
reduce()
some()
Added:
About your following 2nd question,
AMAZING!!!! Would there be a way of capturing these duplicates in a pop up, using reduce() and some()?
When you want to retrieve the duplicated rows, how about the following script? In this case, I thought that filter() is useful instead of some().
Modified script:
var obj = entryVlArray.reduce((o, e) => Object.assign(o, {[JSON.stringify(e)]: true}), {});
// var duplicate = dbArray.some(e => obj[JSON.stringify(e)]);
var duplicatedRows = dbArray.filter(e => obj[JSON.stringify(e)]);
console.log(duplicatedRows)
In this modified script, you can see the duplicated rows at the log.
About a pop up you expected, if you want to open a dialog including the duplicated rows, how about adding the following script after the line of var duplicatedRows = dbArray.filter(e => obj[JSON.stringify(e)]);?
Browser.msgBox(JSON.stringify(duplicatedRows));
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)
I'm trying to build a list of Urls. The structure is like this:
http://somedomain.com/game_CATEGORY?page=NUMBER.
I have an array of game categories, ranging from action games category to word games category.
I have an array of numbers, 1 through 20.
I have pieces of the url saved as strings.
I've been trying for a day to combine them in this way:
cats = ["action","adventure","arcade","board","card","casino","casual","educational","family","music","puzzle","racing","role_playing","simulation","sports","strategy","trivia","word"],
nums = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],
urlString1 = "http://example.com/game_",
urlString2 = "?page=",
madeUrl1 = [],
x = 1, // counter for page numbers
madeUrl2 = [];
for (var i = 0; i < cats.length; i++) {
madeUrl1.push(urlString1+cats[i]+urlString2);
};
for (var i = 0; i < madeUrl1.length; i++) {
madeUrl2.push(madeUrl1[i]+x);
x++;
};
console.log(madeUrl2);
This gets me partially there. But its printing out one number per category. I need each category printout to have ALL 20 numbers added, then move on to the next category.
You'd need to nest another for loop inside your second one. Something like:
for (var i = 0; i < madeUrl1.length; i++) {
for (int j = 0; j < nums.length; j++) {
madeUrl2.push(madeUrl1[i]+nums[j]);
}
};
That way you're iterating through the base URLs you prepared in madeUrl1, and then for each of those you're iterating through each number you have in the array.
If the numbers are simply sequential from 1 to 20, you don't even need the nums array:
for (var i = 0; i < madeUrl1.length; i++) {
for (var x = 1; x <= 20; x++) {
madeUrl2.push(madeUrl1[i]+x);
}
};
And the whole thing could be accomplished with a single nested for loop:
for (var i = 0; i < cats.length; i++) {
for (var x = 1; x <= 20; x++) {
madeUrl1.push(urlString1+cats[i]+urlString2+x);
}
};
You can use the code below:
cats = ["action","adventure","arcade","board","card","casino","casual","educational","family","music","puzzle","racing","role_playing","simulation","sports","strategy","trivia","word"],
nums = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],
urlString1 = "http://example.com/game_",
urlString2 = "?page=",
madeUrl1 = [],
x = 1;
for (var i = 0; i < cats.length; i++) {
for (var j = 0; j < nums.length; j++) {
madeUrl1.push(urlString1+cats[i]+urlString2+nums[j]);
x++;
};
};
console.log(madeUrl1);
What we did here, is first nesting our loops. E.g., it will first loop through the first array, and when it arrives at it first item, in this case a category, it will run the nested loop 20 times, appending each number to the page. After done, it continues to the second category and so on.