Finding the key in a map, given the value - groovy

Hi I have a map like this :
[this:0, is:1, a:2, file:3, anotherkey:4, aa:5]
I wish I could find the key's given the value of a map. For example, if the value 5 is given I need to return aa from the map.
Is that possible?

I don't know if there's a direct method to get a key for a given value, but using Map#find to get a map entry and then get its value should be enough:
def keyForValue(map, value) {
map.find { it.value == value }?.key
}
def map = [a: 1, b: 2, c: 3]
assert keyForValue(map, 2) == 'b'
assert keyForValue(map, 42) == null
In general, maps don't need to have an order relation between their entries, but the default implementation for Groovy's literal maps is LinkedHashMap, which is ordered, so the keyForValue will always yield the first key for a value when using those maps.

There's no specific command for that.
Fortunately, as showed here, you can easily get the key(s) for a specific value in a map:
def myMap = [this:0, is:1, a:2, file:3, fix:4, aa:5]
def myValue = 5
You can do:
def myKey = myMap.find{ it.value == myValue }?.key
// 'aa'
If you want all the keys, do something like this:
def myMap = [this:0, is:1, a:2, file:3, fix:4, aa:5, bb:5]
def myValue = 5
def myKeys = []
myMap.findAll{ it.value == myValue }.each{myKeys << it?.key}
// ['aa', 'bb']

You could invert the map, like this:
Map m = [a: '1', b: '2']
Map mInvert = m.collectEntries { e -> [(e.value): e.key] }
assert mInvert == ['1':'a', '2':'b']
assert mInvert['2'] == 'b'
assert m['b'] == '2'

You'll probably have to iterate over the entry set yourself and try to find the entry with a matching value.

def expect = 5
def m = ['this':0, is:1, a:2, file:3, aa:5]
def r = m.collectMany{ k,v -> (v == expect) ? [k] : []}
// Result: [aa]

Related

To retrieve data from list where it contains dictionary as its values (python)

I am newbie to python, trying to understand the concepts. I am trying to traverse a list, where inside list, I have kept dictionary data set which are initialized. I have defined function to traverse and the retrieve data.
Initially first key and value will be assigned to activeConfiguration list i,e activeConfiguration = ['Mammals','dogs'] and this activeConfiguration is passed as an param for getNextConfig(data, activeConfiguration) function along with entity data.
My goal is that after some certain steps when I make function call getNextConfig(data, activeConfiguration) it should retrieve next value for from the list for the particular key. the expected out I have specified below.
My code has bug, please help me to fix and to get desired result.
Thanks for the help in advance.
#Entity data initialization
vertebrateAnimalsDict = [
{
"Reptiles": "Snakes, lizards, crocodiles, alligators, turtles"
},
{
"Mammals": "dogs, cats, horses, duckbill platypuses, kangaroos, dolphins, whales"
},
{
"Minibeasts": "Insects, spiders, crustaceans"
}
]
My function calls :
activeConfiguration = ['Mammals','dogs']
activeConfiguration = getNextConfig(vertebrateAnimalsDict, activeConfiguration)
print(activeConfiguration)
#some tasks in between
...
activeConfiguration = getNextConfig(vertebrateAnimalsDict, activeConfiguration)
print(activeConfiguration)
#some other tasks inbetween
...
activeConfiguration = getNextConfig(vertebrateAnimalsDict, activeConfiguration)
print(activeConfiguration)
My CODE :
#!/usr/bin/env python
def getNextConfig(data, activeConfiguration):
key_count=len([ele for ele in data if isinstance(ele,dict)])
val_index=-1
for dic in data:
for k,v in dic.items():
if k==activeConfiguration[0]:
key_index=next((i for i,d in enumerate(data) if k in d), None)
v=data[key_index][k]
v = v.split(',')
val_index=v.index(activeConfiguration[1])
if val_index != (len(v)-1):
return [k,v[val_index+1]]
elif key_index==(key_count-1) and val_index == (len(v)-1):
return []
else:
val_index=0
key_index=key_index+1
break
if val_index==0:
v=data[key_index][k]
v = v.split(',')
return [k,v[val_index]]
else:
continue
My Expected Output result :-
Reptiles : Snakes
Reptiles : lizards
Reptiles : crocodiles
Reptiles : alligators
Reptiles : turtles
Mammals : dogs
Mammals : cats
and so on ...
It would be simple to do the following:
Create one dictionary from the list of dictionaries:
dict1 = {k: v.split(", ") for x in vertebrateAnimalsDict for k, v in x.items()}
EDIT:
Convert this to a series and explode (so each item in the list of values is on a different row):
pairs = pd.Series(dict1).explode()
This small function:
def getNextConfig(pair):
# get list of bools for whether item matches, and "shift"
x = pairs[[False] + list(pairs == pair[1])[:-1]]
# print the pair, for example
print([x.index.item(), x.item()])
# return the pair
return [x.index.item(), x.item()]
Then running the code from the start:
pair = ["Reptiles", "Snakes"]
pair = getNextConfig(pair) # repeat this line to the end (and error on the very last, where it cannot continue)
And the old answer's loop, just in case you decide that you will loop through every combination or want to do this in the future:
for k, v in dict1.items():
for idx in range(len(v)):
print([k, v[idx]])
# the other code here...
EDIT 2:
Without the use of Pandas, you can instead "flip" the dictionary:
pairs = {}
for k, v in dict1.items():
for idx in range(len(v)):
pairs.update({v[idx]: k})
As all the items in the lists for reptiles, mammals, and minibeasts will be unique, you can change the values to keys and these three categories to values.
Then when calling the function you can reverse these when returning the pair (I have written a list comprehension to search the list of keys, "animals", instead of searching for values in a Pandas Series):
def getNextConfig(pair):
# get list of bools for whether item matches, and "shift"
p = [i+1 for i, y in enumerate(pairs.keys()) if y==pair[1]][0]
if len(pairs.keys()) <= p:
# print statement if out of items
print("Previous pair was last pair")
# return same pair (i.e. the last pair)
return pair
# animal
x = list(pairs.keys())[p]
# print the pair
print([pairs[x], x])
# return the pair
return [pairs[x], x]
Note that I have included an if statement for the last pair so that you a specific message can be written.
If I understand your question correctly, you could just use a generator to iterate the values:
def getNextConfig(data):
for dic in data:
for key, value in dic.items():
values = value.split(', ')
for v in values:
yield key, v
You might then loop over it like this:
configs = getNextConfig(vertebrateAnimalsDict)
for k, v in configs:
print(f'{k} : {v}')
Output (for your sample data):
Reptiles : Snakes
Reptiles : lizards
Reptiles : crocodiles
Reptiles : alligators
Reptiles : turtles
Mammals : dogs
Mammals : cats
Mammals : horses
Mammals : duckbill platypuses
Mammals : kangaroos
Mammals : dolphins
Mammals : whales
Minibeasts : Insects
Minibeasts : spiders
Minibeasts : crustaceans
Or to match your code style in the question, we use next to fetch the next value from the generator:
configs = getNextConfig(vertebrateAnimalsDict)
activeConfiguration = next(configs, None)
if activeConfiguration is not None:
# do something with it
Note we supply a default value to next to avoid a StopIteration error.

Pick elements on (un)even index from an array in Groovy

I have a Groovy array containing digits of a number. I need to create two new arrays containing only the digits at even resp. uneven positions from that array.
The best way that I could find is this, but I feel there's quite a lot of room for improvement here:
def evenDigits = digits
.indexed(1)
.findAll { i, v -> i % 2 == 0 }
.collect { it.value }
Obviously the unevenDigits variant would be to simply check the modulus in the findAll closure against 1 instead of 0.
Does anyone know if this code can be improved or compacted?
A "less smarter" (and definitely more performant) solution:
def evens = [], odds = []
digits.eachWithIndex{ v, ix -> ( ix & 1 ? odds : evens ) << v }
You can use groupBy to separate the results to odd/even items. E.g.
groovy:000> ["a","b","c"].indexed(1).groupBy{ i, _ -> i & 1 }.collectEntries{ k, v -> [k as Boolean, v.values()] }
===> [true:[a, c], false:[b]]
One more "Groovy" solution that uses withIndex() and findResults() combination.
withIndex() transforms a List<T> to List<Tuple2<T,Integer>> - a list of value-index tuples.
findResults(closure) runs filtering transformation - the closure it receives is a transforming predicate. In our case, it checks if the index value is odd or even and extracts the value from tuple if the predicate matches. (All null values are filtered out.)
Short and concise. Requires a minimal number of transformations: List<T> to List<Tuple2<T,Integer>> and then a single iteration to produce the final result.
def numbers = [1,2,3,4,5,6,2,3,1] // Some test data
def even = { t -> t.second % 2 == 0 ? t.first : null } // "Even" transforming predicate
def odd = { t -> t.second % 2 == 1 ? t.first : null } // "Odd" transforming predicate
def evens = numbers.withIndex(1).findResults even
def odds = numbers.withIndex(1).findResults odd
// And some assertions to test the implementation
assert evens == [2,4,6,3]
assert odds == [1,3,5,2,1]
Another option, for a single pass (but still with the intermediate collection due to indexed), would be a reduce:
def (odd,even) = digits.indexed().inject([[],[]]){ acc, it -> acc[it.key&1] << it.value; acc }
I came up with this, but it's probably not the cleverest way.
def isEven = { int x -> x % 2 == 0 ? x : null}
def (digits, evens, odds) = [[1, 2, 3, 4, 5, 6, 7, 8, 9], [], []]
digits.each {
if (isEven(it))
evens.add(isEven(it))
}
odds = digits - evens
assert evens == [2, 4, 6, 8]
assert odds == [1, 3, 5, 7, 9]

Look ahead in a for loop iterating through a string?

I have a simple for loop iterating through a user input string. If the it encounters a certain value, I want to be able to look ahead at the next value in order to determine what to do next. What is the best way to accomplish this? For example in my code below, if it encounters a "1" in the string, it should look at the next character in the string. If it is also a 1, print 1. Otherwise do nothing.
UserInput = input("Enter calculator expression:")
for x in UserInput:
...
...
if x == 1:
# if the next value in the string is 1:
# print 1
# else:
# do nothing
Use range and len in the loop to get position address
UserInput = input("Enter calculator expression")
for i in range(len(UserInput)-1):
if x[i]=='1':
if x[i+1]=='1':
print "something"
else:
pass
You can zip a string with itself, but offset with a slice.
>>> from itertools import zip_longest
>>> the_input = 'foobar' # example
>>> the_input[1:] # slice off the first character
'oobar'
>>> for c, lookahead in zip_longest(the_input, the_input[1:]):
... print(c, lookahead)
...
f o
o o
o b
b a
a r
r None
This is more Pythonic than using an index like you would in a language like C.
Zipping pairs things elementwise, like the teeth of a zipper.
You can user enumerate() function.
something like this,
#!/user/bin/python3
for i,x in enumerate(UserInput):
if x=='1':
if UserInput[i+1] == '1':
print('1')
Firstly, python convention is snake-case (user_input instead)
code below is my solution
from itertools import islice
def window(seq, n=2):
it = iter(seq)
result = tuple(islice(it, n))
if len(result) == n:
yield result
for elem in it:
result = result[1:] + (elem,)
yield result
pair = list(window(user_input))
comparison_list = ["1"]
result = [x for x,y in pair if x in comparison_list and x == y]
You don't need to look ahead. At least it is not what we usually do when we tackle this kind of problem. Instead, you should look backward - by storing the information. The following example stores the information in a variable state and you can decide the next action in the subsequent iteration.
UserInput = input("Enter calculator expression:")
state = '0'
for x in UserInput:
if x == '1':
if state == '1':
print('1')
else:
state = '1'
else:
state = '0'
A different (probably more pythonic) way of doing this with the zip function:
for char, next_char in zip(UserInput, UserInput[1:]):
if char == "1" and char == next_char:
print(1)
prev_char = None
for char in input("Enter calculator expression:"):
pass # Here you can check the current character and the previous character
if 1 == prev_char and 1 == char:
print(1)
prev_char = char

How to get keys from nested dictionary of arbitrary length in Python

I have a dictionary object in python. Let's call it as dict. This object could contain another dictionary which may in turn contain another dictionary and so on.
dict = { 'k': v, 'k1': v1, 'dict2':{'k3': v3, 'k4':v4} , 'dict3':{'k5':v5, dict4:{'k6':v6}}}
This is just an example. Length of outermost dictionary could be anything. I want to extract keys from such dictionary object in following two ways :
get list of only keys.
[k,k1,k2,k3,k4,k5,k6]
get list of keys and its parent associated dictionary so something like this :
outer_dict_keys = [k ,dict2, dict3]
dict2_keys = [k3,k4]
dict3_keys = [k5, dict4]
dict4_keys = [k6]
Outermost dictionary dict length is always changing so I can not hard code anything.
What is best way to achieve above result ?
Use a mix of iteration and tail recursion. After quoting undefined names, making spacing uniform, and removing 'k2' from the first result, I came up with the code below. (Written and tested for 3.4, it should run on any 3.x and might on 2.7.) A key thing to remember is that the iteration order of dicts is essentially random, and varies with each run. Recursion as done here visit sub-dicts in depth-first rather than breadth-first order. For dict0, both are the same, But if dict4 were nested in dict2 rather than dict3, they would not be.
dict0 = {'k0': 0, 'k1': 1, 'dict2':{'k3': 3, 'k4': 4},
'dict3':{'k5': 5, 'dict4':{'k6': 6}}}
def keys(dic, klist=[]):
subdics = []
for key in sorted(dic):
val = dic[key]
if isinstance(val, dict):
subdics.append(val)
else:
klist.append(key)
for subdict in subdics:
keys(subdict, klist)
return klist
result = keys(dict0)
print(result, '\n', result == ['k0','k1','k3','k4','k5','k6'])
def keylines(dic, name='outer_dict', lines=[]):
vals = []
subdics = []
for key in sorted(dic):
val = dic[key]
if isinstance(val, dict):
subdics.append((key,val))
else:
vals.append(key)
vals.extend(pair[0] for pair in subdics)
lines.append('{}_keys = {}'.format(name, vals))
for subdict in subdics:
keylines(subdict[1], subdict[0], lines)
return lines
result = keylines(dict0)
for line in result:
print(line,)
print()
expect = [
"outer_dict_keys = ['k0', 'k1', 'dict2', 'dict3']",
"dict2_keys = ['k3', 'k4']",
"dict3_keys = ['k5', 'dict4']",
"dict4_keys = ['k6']"]
for actual, want in zip(result, expect):
if actual != want:
print(want)
for i, (c1, c2) in enumerate(zip(actual, want)):
if c1 != c2:
print(i, c1, c2)

Good Way to Filter Object in a List Which A property Equal B property in Two Object

I have list of Objects(Name A), A have property B and C. I need to find the object in the list which B property equal with another object's C property. For Example:
def objectList = [A1,A2,A3,A4,A5,A6,A7,A8];
if A1.B == A2.C then return A1,A2;
Any good way to do that?
You can use the findAll method for this:
def list = []
def matching = list.findAll { A a ->
a.B == a.C
}
Update
You can get all the pairs of matching objects this way:
def matching = []
list.unique { A a1, A a2 ->
if (a1.B == a2.C || a1.C == a2.B) {
matching << a1 << a2
}
return 1
}
This is kind of a hacky solution since it does not use the unique method as intended.
Not sure whether you want your result flattened or not, anyway here's a solution returning a list of tuples:
def result = list.inject([]) {acc,a1->
list.each {a2->
if (!a1.is(a2) && a1.b == a2.c) {
acc << [a1,a2]
}
}
acc
}

Resources