How to get only unique values of a 2d array - google-apps-script

I need to get the following 2d array from:
[[Option 10, 2.0], [Option 10, 2.0], [Option 9, 1.0], [Option 7, 1.0]]
to
[[Option 10, 2.0], [Option 9, 1.0], [Option 7, 1.0]]
I found this post (Splitting a 2D array using some() , by date, avoiding duplicates. Just want 1 unique email, not row. Where am i wrong here?) that has a very efficient way of getting unique values, but I cannot figure out how to apply it to my situation.

Your use case is simpler than the one you refer to.
try this for example :
function myFunction() {
var source = [['Option 10', 2], ['Option 10', 2], ['Option 9', 1], ['Option 7', 1]];
var dest = [];
dest.push(source[0]);
for(var n = 1 ; n< source.length ; n++){
if(dest.join().indexOf(source[n].join()) == -1){dest.push(source[n])};
}
Logger.log(dest);
}

Because 'unique' is not always simple to describe, I often use a pattern which is is, in effect, a variation of Serge's correct answer using ES5 array map/filter functions.
An edited version:
function hash(arr) {
// in this case the hash method is the same as Serge's Array.join() method,
but could be customised to suit whatever condition you need to generate
bespoke comparators such as where `1 + 3` should match `2 + 2`, or where
particular columns in the array can be omitted
return arr.join();
}
function myFunction() {
var source = [['Option 10', 2], ['Option 10', 2], ['Option 9', 1], ['Option 7', 1]];
var hash = source.map(
function (row) {
return hash(row);
}
);
source = source.filter(
function (filterRow, i) {
return hash.slice(0, i).indexOf(hash(filterRow)) < 0;
}
);
Logger.log(source);
}
I only include this as there are times when your comparison may need to flex a little. In your example this isn't important which is why Serge's is correct, but I share to show a potential expansion food for thought for when unique needs to be 'tweaked'

Related

Values from a Range not coming up as an array

I am unable to obtain an array from a getRange.getValues call to some data on a sheet, i.e. no brackets []. If I just create an array in the code I am OK. I am trying to use indexOf to locate a specific date. In my real code the date to match is also plucked from the sheet.
In the following test code the vars are global and not shown here.
function testArray() {
var rowTwoDates = playgroundSheet.getRange(2, 59, 1, 5).getValues();
var strippedRowTwoDates = rowTwoDates[0].map(stripTime);
Logger.log('array: ' + strippedRowTwoDates);
Logger.log('indexOf: ' + strippedRowTwoDates[0].indexOf("06/09/2022"));
var scores = [10, 20, 30, 10, 40, 20];
Logger.log(scores); // 2
Logger.log(scores.indexOf(30)); // 2
}
9:38:23 AM Notice Execution started
9:38:24 AM Info array: 06/07/2022,06/08/2022,06/09/2022,06/10/2022,06/11/2022
9:38:24 AM Info indexOf: -1
9:38:24 AM Info [10.0, 20.0, 30.0, 10.0, 40.0, 20.0]
9:38:24 AM Info 2.0
9:38:24 AM Notice Execution completed
You're only checking indexOf for the first value in the array here:
Logger.log('indexOf: ' + strippedRowTwoDates[0].indexOf("06/09/2022"));
I think you want to do this:
Logger.log('indexOf: ' + strippedRowTwoDates.indexOf("06/09/2022"));

Best approach to get multiple keys from an immutable map?

What is the best way to get multiple values from an immutable map?
const example = new Map({
id: 1,
first: 'John',
last: 'Smith',
age: '99',
gender: 'M',
children: new List([7,8,10]),
});
Using toJS() has been an approach:
const {
first,
last,
age,
gender
} = example.toJS();
But if I were to pull in children it would no longer be an immutable list.
Using get():
const first = example.get('first');
const last = example.get('last');
...
This maintains the type of children, but seems like extra cycles and key strokes.
Any thoughts?
I know this can be an opinionated question, but I'm looking for something with merit, please include stats (key strokes, cycles) to support your answer.
Personally I would probably just stick with the .get()s, but if you want to be able to use destructruing, you could try the .toJSON() method. It's like .toJS() but it only does a shallow conversion to either an object or an array. You could also use .toObject() or .toArray() if you know what type you'd like to turn it into (which you must if you're destructuring it).
const m = Immutable.fromJS({
a: {a2: 'a3'},
b: [1, 2, {f: 'f'}],
});
const { a, b } = m.toJSON();
console.assert(Immutable.isImmutable(a) && Immutable.isImmutable(b));
console.log('a =', a);
console.log('b =', b)
const [ c, d, e ] = b.toArray();
console.assert(c == 1 && d == 2 && Immutable.isImmutable(e));
const { f } = e.toObject();
console.assert(f === 'f');
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/4.0.0-rc.9/immutable.js"></script>
I made a jsperf since you mentioned you wanted stats. For me using Chrome 63 on a MacBook Pro, .get is about 3x as fast as .toJSON

what is the best way to zip multiple lists in ImmutableJS

Assume i have a List of Lists. e.g:
const l : List<List<number>> = fromJS([[0,1,2,3],[4,5,6,7],[8,9,10,11]])
what is the best way (without using toJS()) to zip "l" so i'll get:
[[0,4,8],[1,5,9],[2,6,10],[3,7,11]]
I believe you want to use List#zip.
const l = Immutable.fromJS([
[0, 1, 2, 3],
[4, 5, 6, 7],
[8, 9, 10, 11]
]);
const zipped = l.get(0).zip(...l.rest());
console.log(zipped);
// [ [0,4,8], [1,5,9], [2,6,10], [3,7,11] ];
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/4.0.0-rc.9/immutable.js"></script>
Note that this returns a list of Arrays. It's easy enough to turn them into Lists though:
const zippedLists = zipped.map(List);
You might also be interested in List#zipAll if you're zipping lists of different sizes.

Google charts api - joining 3 json strings using google.visualization.data.join

I want to parse 3 separate data sets to my chart.draw() function. I've read that this is not possible so I must use the google.visualization.data.join() function to join them together. How ever I seem to be having trouble joining 3 json strings.I've tried this (as the function only takes two variables):
var joinedData1 = google.visualization.data.join(json1, json2, 'full', [[0, 0]], [1], [1]);
var joinedData2 = google.visualization.data.join(joinedData1, json3, 'full', [[0, 0]], [1], [1]);
But when I draw the chart it seems to only draw the lines of "json1" and "json3".
How can I draw the 3 lines from separate datasets?
Any help would be really appreciated.
I ran into the same issue but i'm not using JSON strings. The problem here is
google.visualization.data.join(dt1, dt2, joinMethod, keys, dt1Columns, dt2Columns);
You have mentioned only one column of dt1(joinedData1) so only the first column of the joinedData1 is joined with json3
Current:-
var joinedData1 = google.visualization.data.join(json1, json2, 'full', [[0, 0]], [1], [1]);
var joinedData2 = google.visualization.data.join(joinedData1, json3, 'full', [[0, 0]], [1], [1]);
To be changed :-
var joinedData2 = google.visualization.data.join(joinedData1, json3, 'full', [[0, 0]], **[1,2]**, [1]);

Select from createListBox with ScriptDb

I have this code in input:
utentiGrid.setWidget(1, 2, app.createLabel('Stato:'));
utentiGrid.setWidget(1, 3,
app.createListBox().setName('tipologia').addItem("Alpha").addItem("Beta"));
I select "Beta" and write ScriptDb
Then I take the record and visualize the result by modifying with this code:
utentiGrid.setWidget(1, 2, app.createLabel('Stato:'));
utentiGrid.setWidget(1, 3,
app.createListBox().setName('tipologia').addItem("Alpha").addItem("Beta"));
The problem
I want see my first selection ("Beta") and not "Alpha".
how can I do?
thank you
raffaele
p.s. are not a programmer but scriptDb is fantastic!
Just use the method setSelectedItem as bellow:
function doGet() {
var app = UiApp.createApplication();
var utentiGrid = app.createGrid(3, 4);
utentiGrid.setWidget(1, 2, app.createLabel('Stato:'));
var listBox = app.createListBox().setName('tipologia').addItem("Alpha").addItem("Beta");
//To select Beta use 1 as argument
listBox.setItemSelected(1, true);
utentiGrid.setWidget(1, 3, listBox);
app.add(utentiGrid);
return app;
}
If you change the argument to 0 the item selected will be alpha. If you have a third element, their index will be 2 and so one.