Multiple values to same key in a Groovy Map - list

I am new to both coding and Groovy. I have a requirement to populate a data map values based on the values in a list but with a matching criterion. For e.g. say the 2nd character of the list value is equal to 2, then map it to "Number2" key in the data map. Likewise, I may end up having multiple list values matching this criterion. I am struggling with the below code - it works but it is always picking up the last occurrence of matching value in the list. What I understand is you can only have one unique key-value pair in the map. But is there any other way of achieving this? Sorry, I'm a total rookie here. All the help is appreciated. Thank you!
def map = [:]
def ent = ['123','133','124','143','125']
ent.each{
println it.charAt(1)
}
ent.each{
if(it.charAt(1) == '2'){
println it.charAt(1)
println "is in entity $it"
map['Number2'] = it
map.each{ k, v -> println "${k}:${v}" }
}
}
Expected Result:
['Number2':[123,124,125],'Number3':[133],'Number4':[143]]

I'm probably getting the wrong end of the stick, but do you mean:
def ent = ['123','133','124','143','125']
def map = ent.groupBy { "Number${it.charAt(1)}" }
Edit, with a pre-filter step
def ent = ['123','133','124','143','125']
def map = ent.findAll { it.charAt(1) in ['2', '3'] }
.groupBy { "Number${it.charAt(1)}" }

Related

Groovy groupby List generated from Map values

This is the List that I have
List a = ["Sep->Day02->FY21;Inter01","Sep->Day02->FY21;Inter02","Sep->Day02->FY21;Inter03","Sep->Day01->FY21;Inter18","Sep->Day01->FY21;Inter19"]
I am trying to group this and generate a new string
Expected result
"Sep->Day02->FY21",Inter01:Inter03
"Sep->Day01->FY21",Inter18:Inter19
Tried to do this
List a = ["Sep->Day02->FY21;Inter01","Sep->Day02->FY21;Inter02","Sep->Day02->FY21;Inter03","Sep->Day01->FY21;Inter18","Sep->Day01->FY21;Inter19"]
List b = []
a.each{
b.add(it.split(";"))
}
def c = b.groupBy{it[0]}
println c
c.each{
k, v -> println "${v}"
}
I cant find a way to get the range of Inter01:Inter03 in the string. Please advice.
EDIT
The solution provided by Marmite works in the groovy console as expected. The list I am generating is from values in a map.
a.add(map[z]) Where z is the key.
When I am trying to use it, it gives me max and min method not found errors.
Tried using map[z].toString(). Still the same. Is the fact that the values are from a map affecting the same?
Code Snippet
Below is how I generate the map
def map = [:]
itr.each{
def Per = it.getMemberName("Period") //getMemberName is a product specific function . Sample output May
def Day = it.getMemberName("Day") //Day01 sample output
def Hour = it.getMemberName("Hour") //Interval01 sample output
def HourInt = it.getMemberName("Hour").reverse().take(2).reverse()
def Year = it.getMemberName("Years")
map.put(it.DataAsDate.format("dd/MM/yyyy")+"-"+Hour,Year+"->"+Per+"->"+Day+";"+HourInt)
}
Below is where I generate the List
def OSTinterval = OST.reverse().take(2).reverse() as Integer //This creates 01 out of Interval01
def OETinterval = OET.reverse().take(2).reverse() as Integer //This creates 03 out of Interval03
D1 = new Date(OSDDay)
D2 = new Date(OEDDay)
if (D1 == D2)
{
(OSTinterval..OETinterval).each
{inter ->
z = OSDDay+"-"+"Interval"+inter.toString().padLeft(2,'0')
coll.add(map[z].toString())
}
}
else
{
(D1..D2).each {
if (it == D1){
(OSTinterval..48).each
{inter ->
z = OSDDay+"-"+"Interval"+inter.toString().padLeft(2,'0')
coll.add(map[z].toString())
}
Basically you are looking for min and max after grouping.
I'm using a bit simplified data to focus on the processing:
def a = ['D02;I01','D02;I02','D02;I03','D01;I18','D01;I18']
println a.collect{it.split(";")}
.groupBy{it[0]}
.collect{k,v -> [k,v.collect {it[1]}]}
.collect{[it[0],"${it[1].min()}:${it[1].max()}"]}
.collect{it.join(',')}
returns a list of the keys with the min and max of the values
[D02,I01:I03, D01,I18:I18]
result after groupBy
[D02:[[D02, I01], [D02, I02], [D02, I03]], D01:[[D01, I18], [D01, I18]]]
The next collect removes the duplicated keys
[[D02, [I01, I02, I03]], [D01, [I18, I18]]]
Finally you find the min and max of the lists
[[D02, I01:I03], [D01, I18:I18]]

Find all values in a list of maps that have the key "Oranges"

Still new to groovy here but I am trying to obtain all values from each map in my list of maps that have a key equal to "Oranges"
def resultSet = [
["Oranges":123456, "Apples": "none"],["Oranges":7890, "Apples": "some"]
]
def fruit = resultSet.each{
it.findAll{key, value -> key == "Oranges"}.value
}
println fruit
so for this, I would expect the result to be: [123456, 7890]
but I am getting: [[Oranges:123456, Apples:none], [Oranges:7890, Apples:some]]
The return of the each method is the collection itself. You want to apply some kind of filter on the collection, and not on each of its items. I suggest using findResults, as it will filter out null and empty values:
def resultSet = [
["Oranges":123456, "Apples": "none"],
["Oranges":7890, "Apples": "some"]
]
def fruit = resultSet.findResults { it.Oranges?.value }
assert fruit == [123456, 7890]
There is A simple solution:
def fruit = resultSet.Oranges
assert fruit == [123456, 7890]

Indexing a list of dictionaries for a relating value

I have a 4 dictionaries which have been defined into a list
dict1 = {'A':'B'}
dict2 = {'C':'D'}
dict3 = {'E':'F'}
dict4 = {'G':'H'}
list = [dict1, dict2, dict3, dict4]
value = 'D'
print (the relating value to D)
using the list of dictionaries I would like to index it for the relating value of D (which is 'C').
is this possible?
note: the list doesn't have to be used, the program just needs to find the relating value of C by going through the 4 dictionaries in one way or another.
Thanks!
You have a list of dictionaries. A straightforward way would be to loop over the list, and search for desired value using -
dict.iteritems()
which iterates over the dictionary and returns the 'key':'value' pair as a tuple (key,value). So all thats left to do is search for a desired value and return the associated key. Here is a quick code I tried. Also this should work for dictionaries with any number of key value pairs (I hope).
dict1 = {'A':'B'}
dict2 = {'C':'D'}
dict3 = {'E':'F'}
dict4 = {'G':'H'}
list = [dict1, dict2, dict3, dict4]
def find_in_dict(dictx,search_parameter):
for x,y in dictx.iteritems():
if y == search_parameter:
return x
for i in range(list.__len__()):
my_key = find_in_dict(list[i], "D")
print my_key or "No key found"
On a different note, such a usage of dictionaries is little awkward for me, as it defeats the purpose of having a KEY as an index for an associated VALUE. But anyway, its just my opinion and I am not aware of your use case. Hope it helps.

How to sort python lists due to certain criteria

I would like to sort a list or an array using python to achive the following:
Say my initial list is:
example_list = ["retg_1_gertg","fsvs_1_vs","vrtv_2_srtv","srtv_2_bzt","wft_3_btb","tvsrt_3_rtbbrz"]
I would like to get all the elements that have 1 behind the first underscore together in one list and the ones that have 2 together in one list and so on. So the result should be:
sorted_list = [["retg_1_gertg","fsvs_1_vs"],["vrtv_2_srtv","srtv_2_bzt"],["wft_3_btb","tvsrt_3_rtbbrz"]]
My code:
import numpy as np
import string
example_list = ["retg_1_gertg","fsvs_1_vs","vrtv_2_srtv","srtv_2_bzt","wft_3_btb","tvsrt_3_rtbbrz"]
def sort_list(imagelist):
# get number of wafers
waferlist = []
for image in imagelist:
wafer_id = string.split(image,"_")[1]
waferlist.append(wafer_id)
waferlist = set(waferlist)
waferlist = list(waferlist)
number_of_wafers = len(waferlist)
# create list
sorted_list = []
for i in range(number_of_wafers):
sorted_list.append([])
for i in range(number_of_wafers):
wafer_id = waferlist[i]
for image in imagelist:
if string.split(image,"_")[1] == wafer_id:
sorted_list[i].append(image)
return sorted_list
sorted_list = sort_list(example_list)
works but it is really awkward and it involves many for loops that slow down everything if the lists are large.
Is there any more elegant way using numpy or anything?
Help is appreciated. Thanks.
I'm not sure how much more elegant this solution is; it is a bit more efficient. You could first sort the list and then go through and filter into final set of sorted lists:
example_list = ["retg_1_gertg","fsvs_1_vs","vrtv_2_srtv","srtv_2_bzt","wft_3_btb","tvsrt_3_rtbbrz"]
sorted_list = sorted(example_list, key=lambda x: x[x.index('_')+1])
result = [[]]
current_num = sorted_list[0][sorted_list[0].index('_')+1]
index = 0
for i in example_list:
if current_num != i[i.index('_')+1]:
current_num = i[i.index('_')+1]
index += 1
result.append([])
result[index].append(i)
print result
If you can make assumptions about the values after the first underscore character, you could clean it up a bit (for example, if you knew that they would always be sequential numbers starting at 1).

find all ocurrences inside a list

I'm trying to implement a function to find occurrences in a list, here's my code:
def all_numbers():
num_list = []
c.execute("SELECT * FROM myTable")
for row in c:
num_list.append(row[1])
return num_list
def compare_results():
look_up_num = raw_input("Lucky number: ")
occurrences = [i for i, x in enumerate(all_numbers()) if x == look_up_num]
return occurrences
I keep getting an empty list instead of the ocurrences even when I enter a number that is on the mentioned list.
Your code does the following:
It fetches everything from the database. Each row is a sequence.
Then, it takes all these results and adds them to a list.
It returns this list.
Next, your code goes through each item list (remember, its a sequence, like a tuple) and fetches the item and its index (this is what enumerate does).
Next, you attempt to compare the sequence with a string, and if it matches, return it as part of a list.
At #5, the script fails because you are comparing a tuple to a string. Here is a simplified example of what you are doing:
>>> def all_numbers():
... return [(1,5), (2,6)]
...
>>> lucky_number = 5
>>> for i, x in enumerate(all_numbers()):
... print('{} {}'.format(i, x))
... if x == lucky_number:
... print 'Found it!'
...
0 (1, 5)
1 (2, 6)
As you can see, at each loop, your x is the tuple, and it will never equal 5; even though actually the row exists.
You can have the database do your dirty work for you, by returning only the number of rows that match your lucky number:
def get_number_count(lucky_number):
""" Returns the number of times the lucky_number
appears in the database """
c.execute('SELECT COUNT(*) FROM myTable WHERE number_column = %s', (lucky_number,))
result = c.fetchone()
return result[0]
def get_input_number():
""" Get the number to be searched in the database """
lookup_num = raw_input('Lucky number: ')
return get_number_count(lookup_num)
raw_input is returning a string. Try converting it to a number.
occurrences = [i for i, x in enumerate(all_numbers()) if x == int(look_up_num)]