I'm getting an array back from redis (trhough a controller for my projects) which I need to destructure in my product view.
Array (showing 2 results, but it can many more):
["project-5", "project-4"]
The numbers (5, 4) are my project id's (#project.id) which I need to subtract to use in a .each do function.
All that I can find for it, are destructure solutions for multiple variables. But here I only have 1 variable.
Can anyone help me out with how I can isolate the product id out of this array?
You can use match method to get the ids with the help of regex. Assuming array consists of your projetcs with id-s 3 and 44 then a one-liner would be:
2.0.0-p353 :091 > array.map{|el| el.match(/\d+$/)[0]}
=> ["3", "44"]
If you sure need to use .each do then
array.each do |el|
el.match(/\d+$/)[0]
end
You can also use method gsub with regex to replace everything except the id inside string with an empty string, so only id-part of the string will remain.
One-liner for this (array = ["proj3ct-3", "project-1567"]):
2.0.0-p353 :040 > array.map {|el| el.gsub(/(.*\-)[^\d]*/, "")}
=> ["3", "1567"]
.each do similarly to previous example with match.
EDIT: If you want the do-block to return the array already in formatted form then you should use bang-method from gsub like this: el.gsub!(/(.*\-)[^\d]*/, "") This will also make changes in elements. Non-bang methods only return changed values without altering them.
Just in case you don't know and would like to test/analyze your regex then this is a good place to do it- I've been using it for quite a while. Also a good place to recheck some basics is here
Related
I'd like to know if there's a way to understand if an array contain another array inside him. I ask this question because I'm trying to loop throught two or plus nested arrays but first I need to check this in Angular.
Thanks in advance for the help
var a = [[1,2,3],[4,5,6]]
console.log(Array.isArray(a[0]))
You can check this using Array.isArray function.
There are many ways this can be accomplished, but it depends on the size of the parent array, how deeply nested it's elements are, how does much does performance matter, etc.
If your array only goes one level deep (inner arrays don't contain arrays), you can use these methods:
var arr = [[1,2,3], 'foo', 4, ['foo', 'bar']];
// use .some() to test elements
arr.some((element) => Array.isArray(element));
// returns the index of the first found array, or -1 if no arrays are present
arr.indexOf((element) => Array.isArray(element));
This article gives a pretty good overview of all options, including the performance of each.
I'm using OpenRefine to pull in information on publisher policies using the Sherpa Romeo API (Sherpa Romeo is a site that aggregates publisher policies). I've got that.
Now I need to parse the returned JSON so that those with certain pieces of information remain. The results I'm interested in need to include the following:
'any_website',
'any_repository',
'institutional_repository',
'non_commercial_institutional_repository',
'non_commercial_repository'
These pieces on information all fall under an array called "permitted_oa". For some reason, I can't even work out how to just pull out that array. I've tried writing grel expressions such as
value.parseJson().items.permitted_oa
but it never reutrns anything.
I wish I could share the JSON but it's too big.
I can see a couple of issues here.
Firstly the Sherpa API response items is an array (i.e. a list of things). When you have an array in the JSON, you either have to select a particular item from the array, or you have to explicitly work through the list of things in the array (aka iterate across the array) in your GREL. If you've previously worked with arrays in GREL you'll be familiar with this, but if you haven't
value.parseJson().items[0] -> first item in the array
value.parseJson().items[1] -> second item in the array
value.parseJson().items[2] -> third item in the array etc. etc.
If you know there is only ever going to be a single item in the array then you can safely use value.parseJson().items[0]
However, if you don't know how many items will be in the array and you are interested in them all, you will have to iterate over the array using a GREL control such as "forEach":
forEach(value.parseJson().items, v, v)
is a way of iterating over the array - each time the GREL finds an item in the array, it will assign it to a variable "v" and then you can do a further operation on that value using "v" as you would usually use "value" (see https://docs.openrefine.org/manual/grel#foreache1-v-e2 for an example of using forEach on an array)
Another possibility is to use join on the array. This will join all the things in an array into a string.
value.parseJson().items.join("|")
It looks like the Sherpa JSON uses Arrays liberally so you may find more arrays you have to deal with to get to the values you want.
Secondly, in the JSON you pasted "oa_permitted" isn't directly in the "item" but in another array called "publisher_policy" - so you'll need to navigate that as well. So:
value.parseJson().items[0].publisher_policy[0].permitted_oa[0]
would get you the first permitted_oa object in the first publisher_policy in the first item in the items array. If you wanted to (for example) get a list of locations from the JSON you have pasted you could use:
value.parseJson().items[0].publisher_policy[0].permitted_oa[0].location.location.join("|")
Which will give you a pipe ("|") separated list of locations based on the assumption there is only a single item, single publisher_policy and singe permitted_oa - which is true in the case of the JSON you've supplied here (but might not always be true)
hash_test.pl
#a=("f","a","b");
$K{"f"}{"aa"}=1;
$K{"a"}{"aa"}=1;
$k{"b"}{"bb"}=1;
foreach(#a){
#c= sort keys %{$k{$_}};
}
print "#c\n";
foreach(#c) {...}
perl hash_test.pl
bb
I want to keep the keys of the hash into an array, so that I can use the array as an input for the following statements.
But it seemed that the assay #c just only hold the last element.
Could anyone tell me why or help me to improve the script?
You assign the array every time in the foreach, thus overwriting it every time. So you end up with only having the last thing assigned to it. If you move the print inside the foreach you'll see that they are all there.
To store those keys you need to add them to the array, not assign the array. I've corrected the typo $k to $K, and changed aa that goes with f to ff (expecting it to be a typo as well).
my #c;
foreach my $el (#a) {
push #c, sort keys %{$K{$el}};
}
print "#c\n";
This prints the line: ff aa bb. Every time through the loop all keys found in the hash for a particular array element are added to #c, each as a separate element. So #c will contain all bottom-level keys across the whole data structure.
However, there is more that I would like to suggest.
Always use strict; and use warnings; This is not pedantry but it directly helps. I never write code without them. The typo would be caught here, for example.
Use descriptive variable names. Specifically, single-letter variable names are just too easy to confuse, unless in very short loops or where it is crystal clear what they are. (For example, a typo like this couldn't really happen.) Most importantly, the code is going to be far nicer to work with. That generally results in better code.
Please use good indentation and spacing. It helps a lot, in many ways.
A useful core package for nested data structures is Data::Dumper, which can print the whole thing nicely formatted so we can see it. Try to add to the end of your code
use Data::Dumper;
print Dumper(\%K);
There are yet others that do the same or similar.
Here is another way to do what you ask.
my #lowest_keys = map { sort keys %{$K{$_}} } #a;
I call them lowest_keys to emphasize that these are the ones from the last hash in your data structure, the bottom of it. The map applies processing in the block { ... } to each element of #a in turn, returning a list with all these results. (If any one result itself is a list, with more elements than one, it gets merged into the overall output list. So this may create the output list with many more elements than the input.) This list can then be assigned to an array, as above, or passed on to another function that expects a list as input, or interated over.
The map is generally used to transform an array into another, by doing to each element what is in { ... } block. Its close cousin grep is used to filter, so passing through only the elements of the input list for which the condition in { ... } evaluates to true, forming the output list. For example, filter out undefined array elements: my #good = grep { defined } #all
Variable names are case sensitive, so %K... and %k... are not the same.
Always use
use strict;
use warnings;
and declare your variables with my. That prevents you from making this kind of mistakes.
I use to use the where method from the Collections in backbone. But I don't see how to fetch this result:
MyCollection.Group[x].id
As you can guess, MyCollection is the collection, Group is an array, and id is the field I would like to match for a specific value, something like:
MyCollection.findWhere(Group[x].id: 34);
I have seen the "contains" function of underscore but it doesn't seems to work with associative arrays
Is there a way to do it or should we parse the collection manually using Javascript ?
Collection.where and Collection.findWhere are convenience functions for simple filters. In your case, you would use the more complex Collection.find (proxied to _.find)
find _.find(list, iterator, [context])
Looks through each value in the list, returning the first one that passes a truth test
(iterator). The function returns as soon as it finds an acceptable
element, and doesn't traverse the entire list.
And if I understand correctly your condition, it could look like
MyCollection.find(function(model) {
return _.findWhere(model.get('Group'), {id: 34});
})
you can choose to use jQuery .find() . see examples here: http://api.jquery.com/find/
So what I'm trying to achieve is assign multiple values in to a smarty array on the indexes that I want. It's hard to describe it, so I'll just show it:
{assign var='paymentTypes'
value=','|explode:"$paymentMethods[50],$paymentMethods[51],
$paymentMethods[11],$paymentMethods[10],$paymentMethods[12],
$paymentMethods[99],$paymentMethods[100]"}
(Formatted for readability)
So now I have a paymentTypes array with the values placed on the keys starting from 0. What I want is to keep the keys that were in paymentMethods array - 50, 51, 11.. etc.
And it has to be done totally in Smarty template file. Thanks for any ideas.
I've found a workaround. The needed associative array was for a HTML Select tag. So I just used {html_options} with value and output attributes instead of options. I assigned one array just for values and another just for output.
I had this:
{html_options options=$paymentTypes}
But I didn't want to show all of the values from paymentTypes array, but I had to have them in the array. So what I did was this:
{assign var='paymentTypesOutput' value=','|explode:"$paymentTypes[50],
$paymentTypes[51],$paymentTypes[11],$paymentTypes[10],$paymentTypes[12],
$paymentTypes[99],$paymentTypes[100]"}
{assign var='paymentTypesValues' value=','|explode:"50,51,11,10,12,99,100"}
{html_options values=$paymentTypesValues output=$paymentTypesOutput}
It's not the most elegant solution - but it works.