adjusting linked indexes for reorganized arrays - javascript

I have a table that can be dynamically styled with various colors and a palette of colors that serves as a reference to those colors. When the user has finished coloring, I want to compile the file to JSON. I can fetch the necessary values likewise:
// note _colors is a global variable declared elsewhere
var $rowSelect = $("#rowSelect");
var $colSelect = $("#colSelect");
var $colorBoard = $("#colorBoard");
var $upload = $("#upload");
$upload.on("click", function() {
var numRows = Number($rowSelect.val());
var numCols = Number($colSelect.val());
var pixels = [];
var colors = [];
var comp_colors = [];
var $rows = $colorBoard.children();
for(var i = 0; i < numRows; i++) {
var $cols = $rows.eq(i).children();
for(var ii = 0; ii < numCols; ii++) {
$cell = $cols.eq(ii);
pixels.push(Number($cell.attr("data-colorid")));
}
}
var usedColors = pixels.filter((v, i, a) => a.indexOf(v) === i);
for(var i = 0; i < _colors.length; i++) {
colors.push(_colors[i] ? _colors[i].color.getColor() : null);
if(_colors[i] && usedColors.includes(i) && !comp_colors.includes(colors[i])) comp_colors.push(_colors[i].color.getColor());
}
}
Since colors can be deleted, duplicated, or unused in my UI, I cleaned up my raw color array colors into the comp_colors array. For example, an array of unprocessed colors may look like: [null, "#EF1A1A", null, "#40E255", "#0B1DE3", "#FFFFFF", "#FFFFFF"]. If "#0B1DE3" was not actually present in our pixel array, the cleaned up version would look like: ["#EF1A1A", "#40E255", "#FFFFFF"].
The problem is that cleaning up the color array has offset the indexes that the values of the pixels array were using to reference the colors. For example, using the color situation above, a fetched array of pixels may look like this: [1,3,3,1,5,6,5,1,3,6], but the revised version for the cleaned up color set would be: [0,1,1,0,2,2,2,0,1,0].
What is the most efficient way to correct these values to the appropriate indexes?

I found a concise method, but I don't feel like it is very efficient. I have to iterate through every pixel to achieve this, which can be costly at with large creations. The new list of pixels will be loaded into comp_pixels:
for(var i = 0; i < cells.length; i++) comp_pixels.push(comp_colors.indexOf(colors[pixels[i]]));

Related

Remove duplicate values from flat ARRAY

I'm wanting to remove duplicate values from the array tabData produced by the script below.
I've found numerous posts here that mention "removing duplicates from array", but don't seem to be relevant to my exact goal.
I've tried filter, I've tried using this answer and adjusting the variables to fit my script, but it did not remove the duplicates.
Surely there is a simple function that does exactly what I'm looking for, I'm just not finding it.
function getTabArray() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var version = ss.getRangeByName("version").getValue().toString();
var updateTabsName = "updateTabs";
var updateTabsSheet = ss.getSheetByName(updateTabsName);
var tabDataRows = updateTabsSheet.getLastRow();
var tabDataCols = updateTabsSheet.getMaxColumns() - 1;
var tabDataRange = updateTabsSheet.getRange(1, 2, tabDataRows, tabDataCols);
var tabData = tabDataRange.getValues(); // <-- REMOVE DUPLICATES
for (var i = 0; i < tabData.length; i++) {
if (tabData[0][i] != "" && tabData[0][i] > version) {
for (var j = 0; j < tabData.length; j++) {
if (tabData[j][i] != "" && j > 0) {
Logger.log("tabData[j][i] = " + tabData[j][i]); // tabData[j][i] = all values in column
}
}
}
}
}
This is the array it currently produces:
2.20200514.2,2.20200514.0,2.20200513.2,2.20200513.1,2.20200513.0,2.20200512.0,1.20200405.1,,tabDefinitions,Sheet6,Sheet6,changeLog,Sheet6,Index,,,,Sheet7,,Sheet7,settings,,,,Sheet8,,Sheet8,tabDefinitions,,,,,,,changeLog,,,,,,,updateTabs
I want to remove all duplicates (Sheet6, Sheet7, Sheet8, etc.) from the array.
EDIT:
After one more search, I found this answer which contains exactly what was answered below, but when I use any method in that answer, I still get all duplicates. Not sure what I'm doing wrong or not doing right.
var unique = tabData.filter((v, i, a) => a.indexOf(v) === i);
EDIT 2:
I realized my array was not actually "flat", so I added var tabData = tabDataRange.getValues().flat(); and now everything works!
You can use ES6 Set() function to remove the duplicates
const newArray = [...new Set(arrayWithDuplicates)];

Transferring data by date from email

I'm fairly new to coding in Google Script, and with Javascript. Basically what I'm trying to do is make a script to update data on a table in a spreadsheet. I have the script to import the email as a CSV, but I'm struggling with transferring the data from the email to the table by matching up the dates. Essentially what I would like the script to do is emulate a vlookup and paste the values from the emails CSV file to the table.
I made a copy of the file as an example of what I'm trying to do. I'm trying to transfer the yellow section of columns A and B of the Data tab to the matching yellow section columns A and B. And if there is no data for the dates then I would like the empty dates to be 0.
https://docs.google.com/spreadsheets/d/1uK3sCUFvcW6lgk962jgTN-yZox-lF8-Z0wm7Zhh-i8I/edit?usp=sharing
Thanks!
This two functions will accomplish your objectives. createArray(hight, width, filling) is just a workaround to create an array of the exact size of the Destination table. moveDates() is the one that compares the timestamps of the Data table with the ones on Destination; and will write down the values of the row if they match, and a zero if they don't.
This second function will first declare a bunch of variables that will save ranges and values for both sheets. After that, it will read all the dates of both tables. Later, it will run through the Destination table searching for coincidences and saving them on the newData array. Finally, the code will write down the newData. I've tested this code on your spreadsheet and it works perfectly.
function createArray(hight, width, filling) {
var array = [];
for (var i = 0; i < hight; i++) {
array[i] = [];
for (var j = 0; j < width; j++) {
array[i][j] = filling;
}
}
return array;
}
function moveDates() {
var dataSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Data');
var destinationSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(
'Destination');
var dataRange = dataSheet.getRange(5, 1, 6, 3);
var destinationRange = destinationSheet.getRange(2, 1, 11, 3);
var newDataRange = destinationSheet.getRange(2, 2, 11, 2)
var data = dataRange.getValues();
var destination = destinationRange.getValues();
var dataDates = [];
var destinationDates = [];
var newData = createArray(11, 2, 0);
for (var i = 0; i < data.length; i++) {
dataDates.push(new Date(data[i][0]));
}
for (var i = 0; i < destination.length; i++) {
destinationDates.push(new Date(destination[i][0]));
}
for (var i = 0; i < destination.length; i++) {
for (var j = 0; j < data.length; j++) {
if (destinationDates[i].getTime() === dataDates[j].getTime()) {
newData[i][0] = data[j][1];
newData[i][1] = data[j][2];
}
}
}
newDataRange.setValues(newData);
}
If you need more information or clarifications I'll be happy to help you.

Create multiple instances of an object (by adding incremental numbers to it's name) and addChild to stage

I'm using Canvas/javascript (createjs) and am having difficulty calling an instance or adding a child to stage of a cloned shape (via an array using a for loop adding incremental numbers).
var myShape = new createjs.Shape();
myShape.graphics.f("white").rr(0, 0, 300, 300, 12);
myShape1 = myShape.clone();
myShape2 = myShape.clone();
myShape3 = myShape.clone();
//var arr = [null,cellFlasha1, cellFlasha2, cellFlasha3, cellFlasha4];
var arr = [];
for (var i = 1; i <= 4; i++) {
arr.push(["myShape"+i]);
}
stage.addChild(arr[1]);
I can't seem to add and instance to the stage. It does work when I use the array that has been commented out though. Could it be how i've combined a string and value when I push it to the array as an object?
I know I could just add it to stage by doing stage.addChild(myShape1); etc.. but I want to do it via a loop as there as there will be many more instances to come and similar scenarios (I intend to loop how I add the clones too so the number of objects can just be defined once)
I'm relatively new to javascript so my terminology may not be great. Many thanks in advance. Any help would be much appreciated!
Muzaffar is correct that you can access those variables via the window object, but it is generally a code smell to rely on globals for this kind of thing. Is all you need to get an arbitrary number of those shapes into an array? If so, why not try something like this?
function cloneShapeIntoArray(shape, num) {
var shapeArray = [];
for (var i = 0; i <= num; i++) {
shapeArray.push(shape.clone());
}
return shapeArray;
}
function addShapesToStage(shapes, stage) {
for (var i = 0; i <= shapes.length; i++) {
stage.addChild(shapes[i]);
}
}
var myShape = new createjs.Shape();
myShape.graphics.f("white").rr(0, 0, 300, 300, 12);
var shapes = cloneShapeIntoArray(myShape, 3);
// You can do some extra stuff to the shapes here, eg you could make each one a different scale
// shapes[0].scale = 1
// shapes[1].scale = 1.5
// shapes[2].scale = 2
addShapesToStage(shapes, stage);
That allows you to easily control how many copies you want, and does not pollute the global namespace.
Yes you can do this with "window" global object. Something like this
for(var i=1; i<=4; i++) {
window['myShape'+i] = myShape.clone();
}
var arr = [];
for (var i=1; i<= 4; i++) {
arr.push(window['myShape'+i]);
}
For more detail you can see here:
Use dynamic variable names in JavaScript

Error in loop applying the color to SVG path based on ID using Javascript and

Below is the code that I use to load colors to the svg map that I have based on the winning party taken from a spreadsheet with an array. The problem that I am currently facing is that there is an error in the loop and it identified only the first nine paths and applied the color and left the rest. Can someone help me identify and fix these issues. I am still learning from my mistakes and help would be appreciated.
<![CDATA[
var resultData = [];
var uniqueparty= [];
var wincolor = [];
$.getJSON("https://spreadsheets.google.com/feeds/list/1IoNqeReOPKNFrYMlK2rnJVuMaLeAgnZneLbKYSQ7bs4/od6/public/values?alt=json", function(data) {
var len = data.feed.entry.length;
for (var i=0; i<len; i++) {
//first row "title" column
var current = data.feed.entry[i];
resultData[i]= [
current.gsx$constituency.$t, //0
current.gsx$winner2010.$t, //1
current.gsx$winningparty.$t, //2
current.gsx$candidatename1.$t, //3
current.gsx$party1.$t,//4
current.gsx$candidatename2.$t,//5
current.gsx$party2.$t,//6
current.gsx$candidatename3.$t,//7
current.gsx$party3.$t//8
];
//Moving Winning party names alone to an array
wincolor[i]=[current.gsx$winningparty.$t];
}
//Remove duplicates from the winning party array to another array
uniqueparty = wincolor.filter(function (el) {
if (this[el]) {
this[el] = 1;
return el;
}
return true;
}, {});
//uniqueparty.sort();
//Specify colors for the party
var colors = ["#FE9A2E", "#F2F5A9", "#81F781", "#F2F5A9", "#58ACFA", "#F3F781", "#F5A9F2", "#81F7F3", "#F5A9A9"];
//assign color using loop based on element ID
for(i=0; i<wincolor.length; i++){
for(j=0; j<uniqueparty.length; j++){
if(uniqueparty[j]==resultData[i][2]){
var paths = document.getElementById(resultData[i][0]);
paths.style.fill=colors[j];
break;
}
}
}
});
]]>
I have included the spreadsheet from which the data is retreived and also the svg map
https://docs.google.com/spreadsheets/d/1IoNqeReOPKNFrYMlK2rnJVuMaLeAgnZneLbKYSQ7bs4/pubhtml?gid=0&single=true
http://jsfiddle.net/diviseed/3ncos0uk/1/

string occurrences in a string

I'm am working on a script to count the number of times a certain string (in this case, coordinates) occur in a string. I currently have the following:
if (game_data.mode == "incomings") {
var table = document.getElementById("incomings_table");
var rows = table.getElementsByTagName("tr");
var headers = rows[0].getElementsByTagName("th");
var allcoord = new Array(rows.length);
for (i = 1; i < rows.length - 1; i++) {
cells = rows[i].getElementsByTagName("td");
var contents = (cells[1].textContent);
contents = contents.split(/\(/);
contents = contents[contents.length - 1].split(/\)/)[0];
allcoord[i - 1] = contents
}}
So now I have my variable allcoords. If I alert this, it looks like this (depending on the number of coordinates there are on the page):
584|521,590|519,594|513,594|513,590|517,594|513,592|517,590|517,594|513,590|519,,
My goal is that, for each coordinate, it saves how many times that coordinate occurs on the page. I can't seem to figure out how to do so though, so any help would be much appreciated.
you can use regular expression like this
"124682895579215".match(/2/g).length;
It will give you the count of expression
So you can pick say first co-ordinate 584 while iterating then you can use the regular expression to check the count
and just additional information
You can use indexOf to check if string present
I would not handle this as strings. Like, the table, is an array of arrays and those strings you're looking for, are in fact coordinates. Soooo... I made a fiddle, but let's look at the code first.
// Let's have a type for the coordinates
function Coords(x, y) {
this.x = parseInt(x);
this.y = parseInt(y);
return this;
}
// So that we can extend the type as we need
Coords.prototype.CountMatches = function(arr){
// Counts how many times the given Coordinates occur in the given array
var count = 0;
for(var i = 0; i < arr.length; i++){
if (this.x === arr[i].x && this.y === arr[i].y) count++;
}
return count;
};
// Also, since we decided to handle coordinates
// let's have a method to convert a string to Coords.
String.prototype.ToCoords = function () {
var matches = this.match(/[(]{1}(\d+)[|]{1}(\d+)[)]{1}/);
var nums = [];
for (var i = 1; i < matches.length; i++) {
nums.push(matches[i]);
}
return new Coords(nums[0], nums[1]);
};
// Now that we have our types set, let's have an array to store all the coords
var allCoords = [];
// And some fake data for the 'table'
var rows = [
{ td: '04.shovel (633|455) C46' },
{ td: 'Fruits kata misdragingen (590|519)' },
{ td: 'monster magnet (665|506) C56' },
{ td: 'slayer (660|496) C46' },
{ td: 'Fruits kata misdragingen (590|517)' }
];
// Just like you did, we loop through the 'table'
for (var i = 0; i < rows.length; i++) {
var td = rows[i].td; //<-this would be your td text content
// Once we get the string from first td, we use String.prototype.ToCoords
// to convert it to type Coords
allCoords.push(td.ToCoords());
}
// Now we have all the data set up, so let's have one test coordinate
var testCoords = new Coords(660, 496);
// And we use the Coords.prototype.CountMatches on the allCoords array to get the count
var count = testCoords.CountMatches(allCoords);
// count = 1, since slayer is in there
Use the .indexOf() method and count every time it does not return -1, and on each increment pass the previous index value +1 as the new start parameter.
You can use the split method.
string.split('517,594').length-1 would return 2
(where string is '584|521,590|519,594|513,594|513,590|517,594|513,592|517,590|517,594|513,590|519')

Categories