Cannot get values of a column with getRange and getValues - javascript

Here is the code I have so far:
var items = data.getRange(1,14,1,lc).getValues()[0];
var names = cdata.getRange(52, 1, 28,1).getValues()[0];
When I log 'items' I get the desired information populated in a single array.
When I try to get the 'names' in a column using a similar method I can only get the first cell in a single array or all of the desired cells in an array of arrays.
example of items
[item1,item2,item3,...]
example of names
[name1] or [[name1],[name2],[name3],[...]]
Why am I not able to use the same method to accurately retrieve the names in a column as I did in the row? How do I fix this and get the desired result? How do I get names to return the data in the cells as I did with items?

I see you have 1 column for names combined with []. That will return a [] result from a a structure like [ [][][] ] (not [ [] ]). If your items have multiple rows, you'll get the entire first row [,,,], as you suggest in items.
var items = data.getRange(1,14,1,lc).getValues()[0];
var names = cdata.getRange(52, 1, 28,1).getValues()[0];
That's more a diagnosis than an answer. Basically, you're getting what you should get from that, but I think you want it transposed. Various ways to do that.
But will this work?
// flatten(flatten()) works for 2-level nesting, and so on
function flatten(arrayOfArrays){
return [].concat.apply([], arrayOfArrays);
}
reference: https://gist.github.com/MauricioMoraes/225afcc9dd72acf1511f

You will have to use this instead:
var names = cdata.getRange(52, 1, 28,1).getValues().flat();

Related

Can I do multiple search strings in a single JMESPath search?

I want to be able to perform multiple searches inside a JSON using JMESPath with JavaScript, so I don't have to iterate over the large object for each JMESPath search string I need to perform.
I have this example object (let's call it arrayItem):
{
"domains": ["somedomain.com", "otherdomain.com"],
"subdomains": ["mail", "docs"]
}
I'm trying to query both these fields and collect the data in a new array using JavaScript, like so:
const result = JMESPath.search(arrayItem, ["domains[]", "subdomains[]"])
Where one JMESPath search is "domains[]" and the other is "subdomains[]".
But this does not work. I get null as a result. I have one solution, which is to perform a forEach() function for each of the items, but I don't think this is the optimal way as I have to iterate over a huge dataset x number of times instead of a single search.
This "hacky" solution provides the desired output when pushing each item to an array:
let whatIwantArray = []
jmesSearches = ["domains[]", "subdomains[]"]
jmesSearches.forEach((jmesSearch) => {
const result = JMESPath.search(arrayItem, jmesSearch)
result.forEach((domain) => {
whatIWantArray.push(domain)
})
})
console.log(whatIwantAraay)
The output with the loop, which is also the output expected from the JEMSPath query:
["somedomain.com", "otherdomain.com", "mail", "docs"]
How can this be done?
You can make an array of the two arrays you are interested in, then flatten the resulting array of array with the flatten operator [].
Which gives you the query:
[domains, subdomains][]
And so your JavaScript search ends up being:
const result = JMESPath.search(arrayItem, '[domains, subdomains][]');
This would result in the expected array:
[
"somedomain.com",
"otherdomain.com",
"mail",
"docs"
]

GoogleScript - convert arrays of different lengths into arrays of the same length

To be able to use setValues() instead of setValue on a high number of rows, I would like to know how can I convert all my arrays into arrays of the same length.
During a map function, I create one giant array that looks like this :
const myArray = [[Monday, Tuesday],[Monday,Tuesday,Wednesday],[Friday],[Monday,Friday],[Tuesday,Wednesday,Friday]] // And so on.
At the moment I use a setValue for each item of the array. The next step would be simply to use setValues(), and append an array but the problem is they are all of different lengths.
result.forEach(function(_,index){
currentSheet.getRange(1+index,5).setValue(result[index]);
});
That is going to do that for 600 lines and I will do it several times with other functions. I can live with it, but it seems like a waste. Is there a way to make the arrays homogenous (all arrays would be have a length of 3 elements, one or two being empty for example) an use one single setValues() instead ?
EDIT : the original map function to create the first array was requested. Here it is :
(Basically what it does is : it runs a map through a first array, look at the first element and go find in the source all the elements that have the same key and return the 9th and 10th elements of that array)
const result = UniquesDatas.map(uniqueRow =>
SourceDatas
.filter(row => row[0] === uniqueRow[0])
.map(row => [row[9]+" "+row[10]])
);
Thank you in advance,
Cedric
You can concat an array of empty elements of the remaining length.
const myArray = [['Monday', 'Tuesday'],['Monday','Tuesday','Wednesday'],['Friday'],['Monday','Friday'],['Tuesday','Wednesday','Friday']]
const res = myArray.map(x => x.concat(Array(3 - x.length)));
console.log(res);
As suggested by Kinglish, to get the length of the inner array with the most elements, use Math.max(...myArray.map(x=>x.length)), which will work for the more general case.

How to get an unflattened array of multiselect values and single inputs together?

I have some dynamically created filters on a web app's page where the filter "entry" is at times the combination of a few different inputs and the values for the collection are gathered into an array to send back to the server. If these were all just single inputs then an array of values would be easy to map over to the inputs on the backend, however when one or more is a multiselect with multiple options, a flattened array of values mixing the multiselect's values and the individual input values isn't appropriate.
As an example: if I have two inputs for a given filter on a search control page, one being a multiselect and another being a text input, I would like to gather an array of two elements, the first being an array of selected values and the second as the value entered in the text input. So if in the first multiselect I select "A", "B" and the text input I enter "Joe" and the code below gathers the input values:
Coffeescript:
filters = []
$(#customFilterElements.selector).each ->
filterName = $(#).find('.filter_entry .filter_name:input').val()
filterValues = $(#).find('.filter_entry .filter_value:input').map(->
if $(#).data('multiselect')
$(#).find('option:selected').map(->
$(#).val()
).get()
else
$(#).val()
).get()
filters.push({name: filterName, value: filterValues})
Javascript: (converted from above)
var filters = [];
$(this.customFilterElements.selector).each(function() {
var filterName, filterValues;
filterName = $(this).find('.filter_entry .filter_name:input').val();
filterValues = $(this).find('.filter_entry .filter_value:input').map(function() {
if ($(this).data('multiselect')) {
return $(this).find('option:selected').map(function() {
return $(this).val();
}).get();
} else {
return $(this).val();
}
}).get();
return filters.push({
name: filterName,
value: filterValues
});
});
Current result for filterValues: ["A","B","Joe"]
The above code ends up producing an array ["A","B","Joe"] for filterValues.
I think this may be because the .get() is converting everything to a flattened array. I tried using $.makeArray() instead of .get() and I get the same results but perhaps I missed something.
Desired result for filterValues: [["A","B"],"Joe"]
What I am hoping to produce is [["A","B"],"Joe"] so it is clear that the first element (in this example) is a collection of selected values from a multiselect to the backend.
How can I adjust the above code to get the desired result (for any combination or ordering of multiselects and single inputs together) in a fairly elegant manner?
The code is intended to be applied to any dynamically created filter, so reusable instead of hardcoding to each filter.
Ok, after a full night's rest the answer came to me right away and it seems so obvious now - just need to wrap the multiselect in an array bracket after the .get()! - doh. Sometimes documenting the problem here forces a solution to bubble up or highlight what I was missing.
filters = []
$(#customFilterElements.selector).each ->
filterName = $(#).find('.filter_entry .filter_name:input').val()
filterValues = $(#).find('.filter_entry .filter_value:input').map(->
if $(#).data('multiselect')
[$(#).find('option:selected').map(->
$(#).val()
).get()]
else
$(#).val()
).get()
filters.push({name: filterName, value: filterValues})

Javascript slice isn't giving me correct array length values

Why does it say length 1 instead of 4?
The following is what I'm trying to push and slice. I try and append items.image_urls and slice them into 5 each.
items.image_urls is my dictionary array.
var final_push = []
final_push.push(items.image_urls.splice(0,5))
console.log(final_push.length)## gives me 1...?
var index = 0
final_push.forEach(function(results){
index++ ##this gives me one. I would need 1,2,3,4,5,1,2,3,4,5. Somehting along that.
}
items.image_urls looks like this:
It's an iteration of arrays with image urls.
In your example items.image_urls.splice(0,5) returns an array of items removed from items.image_urls. When you call final_push.push(items.image_urls.splice(0,5));, this whole array is pushed as one item to the final_push array, so it now looks like [["url1", "url2", "url3", "url4", "url5"]] (2-dimensional array). You can access this whole array by calling final_push[some_index].
But what you want instead is to add every element of items.image_urls.splice(0,5) to the final_push. You can use a spread operator to achieve this:
final_push.push(...items.image_urls.splice(0,5));
Spread syntax allows an iterable such as an array expression or string
to be expanded in places where zero or more arguments (for function
calls) or elements (for array literals) are expected
This is exactly our case, because push() expects one or more arguments:
arr.push(element1[, ...[, elementN]])
And here is an example:
let items = {
image_urls: ["url1", "url2", "url3", "url4", "url5", "url6", "url7", "url8", "url9", "url10"]
};
let final_push = [];
final_push.push(...items.image_urls.splice(0,5));
console.log(final_push.length);
console.log(JSON.stringify(final_push));
console.log(JSON.stringify(items.image_urls));
Note: do not confuse Array.prototype.slice() with Array.prototype.splice() - the first one returns a shallow copy of a portion of an array into a new array object while the second changes the contents of an array by removing existing elements and/or adding new elements and returns an array containing the deleted elements.
That seems to be a nested array. So if you would access index 0, and then work on that array like below it will probably work:
console.log(final_push[0].length); //should print 4
The author is mixing up splice and slice. Probably a typo :)
You start at the beginning (0) and then delete 5 items.

using google's data.join to interatively add data to a graph

I'm trying to build a set of data for a Google scatter graph using data.join as follows:
var tempData = newData();
var tempData2 = totalData;
dataArray[dataCount] = tempData;
var joinMark = countArray(dataCount);
totalData = google.visualization.data.join(tempData2,tempData,'full',[[0,0]],[joinMark],[1]);
dataCount = dataCount+1;
Where newData() generates a dataTable from a database, column 0 is always a date and column 1 is always a number. I have been able to get this to work once, to display 2 variables on the graph, but trying to add any more causes my code to fail.
BTW totalData is the variable passed to chart.draw()
The countArray function returns 1 if both arrays have 2 columns (works fine), but for further additions I am returning a comma separated string 1,2... 1,2,3.. etc. This is based on my assumption that that last two variables in data.join are the column numbers from dataTable 1 and 2 respectively to be combined. Am I right in this assumption, or do I need a different variable in that location?
Thanks
Tom
You are correct about the function of the last two parameters in the join call, but you do not want to pass a comma-separated string where joinMark is: that should be an array of column indices, not an array containing a string. You cannot add a comma-separated string to an array to get an array on integers:
var joinMark = '1,2,3';
[joinMark] == [1,2,3]; // false
Change your countArray function to return an array of integers instead, and then pass that array directly to the join function (that is, you shouldn't wrap it in brackets to create an array of arrays):
var joinMark = countArray(dataCount);
totalData = google.visualization.data.join(tempData2,tempData,'full',[[0,0]],joinMark,[1]);

Categories

Resources