Counting instances with same value - javascript

For a project, I need to do some data manipulation in JavaScript.
I need to convert this object:
[
{"source":"stkbl0001","target":"stkbl0005"},
{"source":"stkbl0002","target":"stkbl0005"},
{"source":"stkbl0002","target":"stkbl0005"},
{"source":"stkbl0002","target":"stkbl0005"},
{"source":"stkbl0002","target":"stkbl0005"},
{"source":"stkbl0002","target":"stkbl0005"},
{"source":"stkbl0003","target":"stkbl0005"},
{"source":"stkbl0004","target":"stkbl0005"},
{"source":"stkbl0004","target":"stkbl0005"}
]
to this object:
[
{"source":"stkbl0001","target":"stkbl0005","value":1},
{"source":"stkbl0002","target":"stkbl0005","value":5},
{"source":"stkbl0003","target":"stkbl0005","value":1},
{"source":"stkbl0004","target":"stkbl0005","value":2}
]
(notice that some elements in the first object are same and new field value contains number of repeats)
Basically, I need to detect and count multiple instances, and to create new field value that contains number of instances.
How do I do that?

You can keep track with an object:
var obj = {};
var result = [];
for (var i = 0; i < arr.length; i++) {
var item = arr[i],
key = item.source + '-' + item.target;
if (obj.hasOwnProperty(key)) obj[key].value++;
else {
obj[key] = item;
item.value = 1;
}
}
for (var prop in obj) {
result.push(obj[prop]);
}
In this example, arr is assumed to be your original array, and result is your resulting array.
result will end up being an array of objects that have unique combinations of source and target properties, and value will be the number that those combinations were encountered.

Related

Comparing array from document properties to dataRange not working

So I have a script (google apps script) that pulls data from one of my sheets (to pairs: initials && percentage) that has changing values (sometimes it's only weekly other times it's daily).
It's supposed to check the old values against the new values and only process the new values, but it's processing for all values for some reason.
During the loop process it starts by finding the email attached to that cell and then sends a generated email to the person. Then at the end it stores the new values found over the previous.
Getting New Data & Variables
var data = dataRange.getValues(); // Fetch values for each row in the Range.
var oldData = [{}];
//Declare variable
Getting Old Data from document properties.
var oldValues = PropertiesService.getDocumentProperties().getProperties();
//get values from document properties
var outerArrayOldData = [];
//empty array
var arr4 = [];
//empty array
var thisLoopString,
thisRowArray;
for (var key in oldValues) {
//grabbing keys from document properties 'row[i]' and loop for each
thisLoopString = oldValues[key];
thisRowArray = []; //Reset
array
thisRowArray = thisLoopString.split(","); //Convert the string to partial array
arr4.push(thisRowArray); //Push the inner array into the outer array
outerArrayOldData = arr4.concat(outerArrayOldData); //convert outer to actual usable array
var arr4 = []; //reset arr4 back to 0
};
//End getting old data
Comparing old data to new data
var oldData = outerArrayOldData;
var source = oldData.map(function (row) {
return JSON.stringify(row);
//map array to string
}),
searchRow,
dataLength = data.length;
for (i = 0; i < dataLength; i += 1) {
searchRow = JSON.stringify(data[i]);
if (source.indexOf(searchRow) == -1) {
//search old data and compare to new data using index search and if data isn't in old stack process it through functions
//doing stuff with new pairs
}
}
}
}
How old data is stored to Doc properties.
var objOldData = {};
//empty
var keyName = "",
//empty
thisRowArray;
for (i = 0; i < data.length; i++) {
keyName = "row" + (i).toString();
//set keys
thisRowArray = data[i].toString();
//convert each pair array to string
if (thisRowArray == "") continue;
//skip blanks
objOldData[keyName] = thisRowArray;
//add keys and values to properties as a string
}
PropertiesService.getDocumentProperties().setProperties(objOldData,
true); //true deletes all other properties
//Store the Updated/New Values back to Properties
}
Logger Console:
<<<<<<<<Imported Range data>>>>>>>>
[[BBB, 0.9], [CCC, 0.76], [DDD, 0.89], [, ]]
<<<<<<<<Old data from dpcument properties>>>>>>>>
[[DDD, 0.89], [, ], [BBB, 0.9], [CCC, 0.76]]
<<<<<Processing New Values Not in Old Data>>>>>
[CCC, 0.76]
[BBB, 0.9]
[DDD, 0.89]
<<<<<<<<Store the Updated/New Values back to Properties>>>>>>>>
{row1=CCC,0.76, row0=BBB,0.9, row3=,, row2=DDD,0.89}
As you can see it's still processing all the values even though they are not new and already exist in the system. How come the search isn't finding that they already exist? WHere did I go wrong on this?
In your "Comparing old data to new data" for loop code, try changing:
searchRow = JSON.stringify(data[i]);
to:
searchRow = JSON.stringify([data[i][0], data[i][1].toString()]);
This ensures that the value at the second array index is always converted into a string for comparison to the "old" imported value, which appears to be parsed from a row delivered as a string.
It looks like, currently, new data array values declared with the second value as numeric, (or perhaps null or empty value):
[["BBB", 0.9], ["CCC", 0.76], ["DDD", 0.89], ["",""]];
While "old" rows (imported from Google doc) are imported and converted into an array, where the values are strings:
[["CCC","0.76"],["BBB","0.9"],["",""],["DDD","0.89"]]
On comparing rows with JSON.stringify, for example, '["DDD","0.89"]' does not match '["DDD",0.89]', so all rows are getting erroneously registered as "new".
I did a bit of guessing from your example to arrive at this, but it could be the cause of your bug. Good luck!
I have trouble understanding your code, so I created my own instead:
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var data = {};
function getData() {
var range = sheet.getRange("A1:B3");
var values = range.getValues();
for (var i=0; i < values.length; i++) {
var key = 'row' + i;
var currentRow = values[i];
// for each cell value,
// toString : convert to string
// trim : remove all whitespaces from both ends of cell values
// encodeā€¦ : encode the values so we don't have any ","
var arr = currentRow.map(function(v){return encodeURIComponent(v.toString().trim())});
// join the array with "," delimiter
var s = arr.join();
data[key] = s;
}
} // getData()
function saveData() {
getData();
PropertiesService.getDocumentProperties().setProperties(data);
}
function compareData() {
getData();
var props = PropertiesService.getDocumentProperties().getProperties();
for (var idx in props) {
if (idx in data) {
if (data[idx] != props[idx]) {
Logger.log('\n%s is different\nOld value is "%s"\nNew value is "%s"',
idx,
decodeURIComponent(props[idx]),
decodeURIComponent(data[idx]));
}
} else {
Logger.log('missing row: ' + idx);
}
}
}
// Test function. Check all document properties
function peekProperties() {
var props = PropertiesService.getDocumentProperties().getProperties();
for (var idx in props) {
Logger.log('%s = %s', idx, props[idx]);
}
}
Question: what if a row is deleted? Shouldn't key be the value in A column instead of row number?

Javascript - nested loops and indexes

I am trying to build an array that should look like this :
[
[{"name":"Mercury","index":0}],
[{"name":"Mercury","index":1},{"name":"Venus","index":1}],
[{"name":"Mercury","index":2},{"name":"Venus","index":2},{"name":"Earth","index":2}],
...
]
Each element is the concatenation of the previous and a new object, and all the indexes get updated to the latest value (e.g. Mercury's index is 0, then 1, etc.).
I have tried to build this array using the following code :
var b = [];
var buffer = [];
var names = ["Mercury","Venus","Earth"]
for (k=0;k<3;k++){
// This array is necessary because with real data there are multiple elements for each k
var a = [{"name":names[k],"index":0}];
buffer = buffer.concat(a);
// This is where the index of all the elements currently in the
// buffer (should) get(s) updated to the current k
for (n=0;n<buffer.length;n++){
buffer[n].index = k;
}
// Add the buffer to the final array
b.push(buffer);
}
console.log(b);
The final array (b) printed out to the console has the right number of objects in each element, but all the indexes everywhere are equal to the last value of k (2).
I don't understand why this is happening, and don't know how to fix it.
This is happening because every object in the inner array is actually the exact same object as the one stored in the previous outer array's entries - you're only storing references to the object, not copies. When you update the index in the object you're updating it everywhere.
To resolve this, you need to create new objects in each inner iteration, or use an object copying function such as ES6's Object.assign, jQuery's $.extend or Underscore's _.clone.
Here's a version that uses the first approach, and also uses two nested .map calls to produce both the inner (variable length) arrays and the outer array:
var names = ["Mercury","Venus","Earth"];
var b = names.map(function(_, index, a) {
return a.slice(0, index + 1).map(function(name) {
return {name: name, index: index};
});
});
or in ES6:
var names = ["Mercury","Venus","Earth"];
var b = names.map((_, index, a) => a.slice(0, index + 1).map(name => ({name, index})));
Try this:
var names = ["Mercury","Venus","Earth"];
var result = [];
for (var i=0; i<names.length; i++){
var _temp = [];
for(var j=0; j<=i; j++){
_temp.push({
name: names[j],
index:i
});
}
result.push(_temp);
}
console.log(result)
try this simple script:
var b = [];
var names = ["Mercury","Venus","Earth"];
for(var pos = 0; pos < names.length; pos++) {
var current = [];
for(var x = 0; x < pos+1; x++) {
current.push({"name": names[x], "index": pos});
}
b.push(current);
}

slice string to pieces and store each in new array

Help needed.
I have string like ["wt=WLw","V5=9jCs","7W=71X","rZ=HRP9"] (unlimited number of pairs)
I need to make an array with pair like wT (as index) and WLw as value, for the whole string (or simpler wT as index0, WLw as index 1 and so on)
I'm trying to do it in JavaScript but I just cant figure out how to accomplish this task.
Much much appreciate your help!!
You cannot have a string as an index in an array, what you want is an object.
All you need to do is loop over your array, split each value into 2 items (key and value) then add them to an object.
Example:
// output is an object
var output = {};
var source = ["wt=WLw","V5=9jCs","7W=71X","rZ=HRP9"];
for (var index = 0; index < source.length; index++) {
var kvpair = source[index].split("=");
output[kvpair[0]] = kvpair[1];
}
If you wanted an array of arrays, then its much the same process, just pushing each pair to the output object
// output is a multidimensional array
var output = [];
var source = ["wt=WLw","V5=9jCs","7W=71X","rZ=HRP9"];
for (var index = 0; index < source.length; index++) {
output.push(source[index].split("="));
}
Update If your source is actually a string and not an array then you will have to do a little more splitting to get it to work
var output = {};
var sourceText = "[\"wt=WLw\",\"V5=9jCs\",\"7W=71X\",\"rZ=HRP9\"]";
// i have escaped the quotes in the above line purely to make my example work!
var source = sourceText.replace(/[\[\]]/g,"").split(",");
for (var index = 0; index < source.length; index++) {
var kvpair = source[index].split("=");
output[kvpair[0]] = kvpair[1];
}
Update 2
If your desired output is an array of arrays instead of an object containing key-value pairs then you will need to do something like #limelights answer.
Object with Key-Value pairs: var myObject = { "key1": "value1", "key2": "value2" };
with the above code you can access "value1" like this myObject["key1"] or myObject.key1
Array of Arrays: var myArray = [ [ "key1", "value1"] ,[ "key2", "value2" ] ];
with this code, you cannot access the data by "key" (without looping through the whole lot to find it first). in this form both "key1" and "value1" are actually values.
to get "value1" you would do myArray[0][1] or you could use an intermediary array to access the pair:
var pair = myArray[0];
> pair == ["key1", "value1"]
> pair[0] == "key1"
> pair[1] == "value1"
You can use a for each loop on both types of result
// array of arrays
var data = [ [ "hello", "world"], ["goodbye", "world"]];
data.forEach(function(item) {
console.log(item[0]+" "+item[1]);
});
> Hello World
> Goodbye World
// object (this one might not work very well though)
var data = { "hello": "world", "goodbye": "world" };
Object.keys(data).forEach(function(key) {
console.log(key+" "+data[key]);
});
> Hello World
> Goodbye World
The normal for loop would do perfectly here!
var list = ["wt=WLw","V5=9jCs","7W=71X","rZ=HRP9"];
var pairs = [];
for(var i = 0; i < list.length; i++){
pairs.push(list[i].split('='));
}
This would give you an array of pairs, which I assume you want.
Otherwise just get rid of the outer Array and do list[i].split('=');
If you want it put into an object ie. not an Array
var pairObject = {};
for(var i = 0; i < list.length; i++){
var pair = list[i].split('=');
pairObject[pair[0]] = pair[1];
}

JavaScript: convert objects to array of objects

I have thousands of legacy code that stores array information in a non array.
For example:
container.object1 = someobject;
container.object2 = someotherobject;
container.object3 = anotherone;
What I want to have is:
container.objects[1], container.objects[2], container.objects[3] etc.
The 'object' part of the name is constant. The number part is the position it should be in the array.
How do I do this?
Assuming that object1, object2, etc... are sequential (like an array), then you can just iterate through the container object and find all the sequential objectN properties that exist and add them to an array and stop the loop when one is missing.
container.objects = []; // init empty array
var i = 1;
while (container["object" + i]) {
container.objects.push(container["object" + i]);
i++;
}
If you want the first item object1 to be in the [1] spot instead of the more typical [0] spot in the array, then you need to put an empty object into the array's zeroth slot to start with since your example doesn't have an object0 item.
container.objects = [{}]; // init array with first item empty as an empty object
var i = 1;
while (container["object" + i]) {
container.objects.push(container["object" + i]);
i++;
}
An alternate way to do this is by using keys.
var unsorted = objectwithobjects;
var keys = Object.keys(unsorted);
var items = [];
for (var j=0; j < keys.length; j++) {
items[j] = unsorted[keys[j]];
}
You can add an if-statement to check if a key contains 'object' and only add an element to your entry in that case (if 'objectwithobjects' contains other keys you don't want).
That is pretty easy:
var c = { objects: [] };
for (var o in container) {
var n = o.match(/^object(\d+)$/);
if (n) c.objects[n[1]] = container[o];
}
Now c is your new container object, where c.object[1] == container.object1

array spliting based on our requirement

My array contains the values with comma as separator, like
array={raju,rani,raghu,siva,stephen,varam}.
But i want to convert into the below format like
array = {raju:rani raghu:siva atephen:varam}.
please give some logic to implement this one.
If you're starting with a string, you can split it upon comma:
var myString = 'raju,rani,raghu,siva,stephen,varam';
var array = myString.split(',');
Given that, you can do the following:
var array = [ 'raju', 'rani', 'raghu', 'siva', 'stephen', 'varam' ];
var result = {};
for(var i = 0; i < array.length; i+= 2) {
result[array[i]] = array[i+1];
}
... which gives the answer you've requested.
Keep in mind that if the array is not evenly divisible by 2, the value of the last item will be undefined.
This is how to convert array to key-value pair of objects (odd-index is key, even-index is value in the resulting key-value pairs)
var array = ['raju', 'rani', 'raghu','siva','stephen','varam'],
pairs = {};
for (var i = 0; i < array.length; i += 2) {
pairs [array[i]] = array[i + 1];
}

Categories

Resources