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

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"
]

Related

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 loop over an Array and find part that is included in the Item not the whole item?

I am building a weather app so I need to grab the icon that is matching the call from API. I'm using parcel and parcel dumps all the images in dist folder. I import all the images and that gives me an object which I converted in a one dimensional Array. Because Parcel gives some extra text I can't grab the proper image.
This is the array that I can see:
[0: "/01d.b9bbb2b9.svg" 1: "/01n.2290e7c6.svg" 2: "/02d.ac486e56.svg" 3: "/02n.259589cf.svg"]
<img src="${result.weather.icon}" alt="" class="weather--icon" />//I like to render it like this.
Is there a way I can loop over an array and get only the icon that is matching result.weather.icon ??? I need to find only the 01d or 02d from the array.
It isn't really clear what you are asking - because [0: "/01d.b9bbb2b9.svg" 1: "/01n.2290e7c6.svg" 2: "/02d.ac486e56.svg" 3: "/02n.259589cf.svg"] isn't a valid array.
However, presuming your array is simply the text elements then you can just use find. i.e.
let data = ["/01d.b9bbb2b9.svg", "/01n.2290e7c6.svg", "/02d.ac486e56.svg", "/02n.259589cf.svg"];
let result = data.find(x => x.startsWith('/01d'));
console.log(result);
Here find is better than filter as find returns the first value that matches from the collection. Once it matches the value in findings, it will not check the remaining values.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
Array.prototype.filter allows you to loop through an array and test its values against a condition. It will then only return the values that have passed that test.
const array = [ "/01d.b9bbb2b9.svg", "/01n.2290e7c6.svg", "/02d.ac486e56.svg", "/02n.259589cf.svg"
];
const targetVal = '01d';
const filteredArray = array.filter(image => image.includes(targetVal)
);

Use Array.map on an 2-dimensional Array

So I have a 2-dimensional Array and want to use a "randomBool" function on each of the elements of the elements in the array.
The "randomBool" function just returns a random boolean:
const randomBool = () => Boolean(Math.round(Math.random()));
this would be the 2-dimensional Array, that I would input:
var test = [
["just","some","random","text"],
[1412,"test",1278391]
]
There is a working for-loop nested in a for-loop:
for (let el of test){
for(let i in el){
el[i] = randomBool();
}
}
I tried this:
test.forEach(el => el.map(el2 => randomBool()));
But it didn't work. Why?
You need to use two nested maps.
const randomBools = test.map(outer => outer.map(inner => randomBool()))
forEach is usually intended to iterate over each item in order to perform some kind of side effect without returning anything and without mutating the original array. For example, printing each item to the console.
map, on the other hand, is intended to take an array and return a new array of the same size, with the values transformed in some way, without mutating the original array. For example, uppercase all the words in a list.
Since you want to return a new 2 dimensional from your existing 2 dimension array with some data transformed, you need to nest your map functions. This will map first over the rows (outer), then the columns (inner). The results of the inner maps will be collected into the outer map and you'll be left with a 2 dimensional array with your new values, all without modifying the original array.

Get data from an array of dictionaries in Javascript

I'm working with a web framework and I'm using variables from Python into Javascript code.
I get next array in Python, which can contain more than one cell with dictionaries inside it:
[[{'lacp_use-same-system-mac': u'no'}, {'lacp_mode': u'passive'}, {'lacp_transmission-rate': u'slow'}, {'lacp_enable': u'no'}]]
I want to be able to access every cell array and, after that, get every keys from the dictionary inside this cell array. Up to now, I only have arrays or dictionaries, so for both cases I did next:
var X = JSON.parse(("{{X|decodeUnicodeObject|safe}}").replace(/L,/g, ",").replace(/L}/g, "}").replace(/'/g, "\""));
Where X is the Python variable. Unfortunately, this does not run with the array I wrote above.
How can I do that?
Thanks beforehand,
Regards.
I want to be able to access every cell array and, after that, get
every keys from the dictionary inside this cell array
If I understood correctly you want to get the keys of a nested array.
Note: your array isn't valid js.
const arrarr = [[{key1: 'val1'}, {key2: 'val2'}], [{key3: 'val3'}, {key4: 'val4'}]];
arrarr.forEach(arr => {
arr.forEach(e => {
Object.keys(e).forEach(k => console.log(k))
})
})
If the depth of nests is of arbitrary depth you can use recursion and check if the child is an array, if it is keep going, else get the keys.

How to use underscore .groupBy function to group an array of json objects based on multiple properties?

I have an array of json objects who results I want to groupBy() based on multiple properties i.e.,
I have:
[
{
prop1:val1,
prop2:val2,
prop3:val3,
prop4:val4
}
]
Now if I just wanted to group by prop1 I guess I could have done :
_.groupBy(givenArray, 'prop1');
Now what should I do if I have to group by prop1,prop2 and prop3, i.e., (prop1 && prop2 && prop3)
Please guide.
You can put that target values to an array, and then form them to string, or just transform them to string form and combine:
_.groupBy(givenArray, function(item) {
var keys = _.pick(item, 'prop1', 'prop2', 'prop3');
// If all are string or number,
// return keys.join('_#%#_'); // this prevent ['ab', 'a'] generate same key to ['a', 'ba'];
return JSON.stringify(keys);
});
JSON.stringify maybe one of the many ways to create a combined key, I'm not sure what your vals is (string, number or else), so I'll just use stringify here.
It really depends on what you want your final structure to be.
If you don't mind a non-flat object structure, you can do nested _.groupBy calls:
var result = _(givenArray) //begin chain
.groupBy('a')
.mapValues(function(groupedByA) {
return _(groupedByA) //begin chain
.groupBy('b')
.mapValues(function (groupedByAAndB) {
return _.groupBy(groupedByAAndB, 'c');
})
.value(); //end chain
})
.value(); //end chain
//Then you can do things like:
result[5][4][3]; //All items where a=5, b=4, and c=3.
Downside here is that there's an extra level of nesting for each property you group by, and result[5][4] will blow up if there aren't any results where a=5 for example. (Though you could use a library like koalaesce for that)
Alternatively, if you want a flat object structure, but don't mind it being a bit ungainly to access the items, then:
var result = _.groupBy(givenArray, function (item) {
return JSON.stringify(_.pick(item, 'a','b','c'));
});
//Much simpler above, but accessed like:
result[JSON.stringify({a: 5, b:4, c:3})]
Much simpler and scales better to grouping by more things... but awkward to work with, since the keys are full JSON strings; but then you also don't have the null issue that the first option has.
You can also, just use _.values or some equivalent to turn the flat object structure into a single array of arrays. Then there's obviously no "random" access to get all items with a given value of a,b, and c, but you can always loop over it.

Categories

Resources