This is my Map
[a: 1, b: 1, c: 2, d: 2, e: 1, f: 2]
I want to group similar values and get:
[1: [a, b, e], 2: [c, d, f]]
My best effort is
myMap.groupBy{it.value}.collectEntries{key, value -> [(key): value.keySet()]}
Anything that is groov'ier?
The following code:
def result = [a: 1, b: 1, c: 2, d: 2, e: 1, f: 2].inject([:].withDefault {[]}) { a, k, v ->
a[v] << k
a
}
println result
prints:
[1:[a, b, e], 2:[c, d, f]]
this uses the groovy Map.inject method which is similar to foldLeft or reduce in other languages and the groovy Map.withDefault method so that when you access a map and a key is not found, a default value of empty list ([]) is returned.
Explanation:
.inject( - go through the map one key-value pair at a time
[:].withDefault {[]} - starting with an empty map which will return an empty list if you access a key that does not exist
) { a, k, v - for each key-value pair, do something with the initial map a
a[v] << k - specifically, add the incoming key as an element in a list (as returned by withDefault) contained in the map under key v.
a - return the modified map so that it is sent in as a in {a, k, v -> in the next iteration
What you have already is already simple and elegant. You can still refine it to
map.groupBy { it.value }.collectEntries { [it.key, it.value*.key ] }
to get the same result.
Related
a = [1,2,3,4,4,2,2]
d = {k: v for v, k in enumerate(a)}
print(d)
Let me rephrase myself.
from the above code what does this line exactly mean.
{k: v for v, k in enumerate(a)}
First you have enumerate(a). This built-in function adds a counter to an iterable and returns it in a form of enumerating object. So for every element in a, it makes a tuple (index, a[index]), where here: index will increase from 0 to 6.
Then for v, k in enumerate(a): we have already seen what enumerate(a) does, now you tell Python that for each loop, the tuple (index, a[index]) is represented by v, k. So v = index and k = a[index].
Then at last we find {k: v for v, k in enumerate(a)}, the accolades tell that you're making a dictionary. The k: v tells you that every loop, you will take k as a key of your dictionary with v the corresponding value. So the dictionary its keys will exist out of the elements of a, with their corresponding value equaling their indexc in the list a.
Now you have to take in mind that in a dictionary, each key can only exist once. So when the program comes across a key that already exists in the dictionary, it will overwrite it. That is why for example the first '2' with index 1, doesn't show up in the dictionary. Because it gets first overwritten by the '2' with index 5, after which this key and its value get overwritten by the last '2' and its index 6.
#i have added 10 as a last item in your list for easy understanding.
a = [1,2,3,4,4,2,2,10]
d = {k: v for v, k in enumerate(a)} #this is a dictionary comprehension
print(d)
where 'k' returns the items in the list one by one and 'v' returns the count for
each item in list starting from 0.
like k-->v
1-->0
2-->1
3-->2
4-->3
4-->4
2-->5
2-->6
10-->7
The output is {1: 0, 2: 6, 3: 2, 4: 4, 10: 7}
as you know dictionary doesnt allow duplicate keys. when any duplicate key
arrives it rewrites the previous one and holds the latest one.
{1: 0, 2: 6, 3: 2, 4: 4, 10: 7}
as we have 1 in only once in the input list we get 1:0
and for 2 we have three values 1,5,6 as 6 is the latest value. we get
2:6
Like wise happens.
I have a python function
func(a, b, c, d, e).
I want to pass this function to another function that evaluates it. The catch is that this other function only varies an arbitrary subset of the parameters (a, b, c, d, e), and the other parameters shall be preloaded with a constant. The parameter order may also change.
For example: I would like func_2 to vary a, c, and d, while b=3 and e=4. So I need a routine
def convert(func, variables=[3, 0, 2], constants=[1, 4], vals=[3, 4]):
...
python magic
...
return func_2
that converts:
func(a, b, c, d, e) -> func_2(d, a, c, b=3, e=4),
so that when I call func_2(1, 2, 3), what is actually called behind the scenes is func(2, 3, 3, 1, 4).
(This is for an optimization algorithm that operates on subspaces of a parameter space, and these subspaces can change from cycle to cycle. func is a cost function.)
How do I code convert in Python 3?
This works:
def convert(func, vars, fixed):
# vars: list of indices
# fixed: dictionary mapping indices to constants
n = len(vars) + len(fixed)
def func_2(*args):
newargs = [None] * n
for i, j in enumerate(vars):
newargs[j] = args[i]
for k in fixed:
newargs[k] = fixed[k]
return func(*newargs)
return func_2
Here you have a possible solution:
def convert(func, var, const, vals):
def func2(*args):
params = [args[var.index(i)] if i in var
else vals[const.index(i)]
for i in range(len(var)+len(const))]
return func(*params)
return func2
It works with any number of parameters
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]
Is there an easy way to search for a sequence of strings in a list? For example:
testlist = [a,b,c,d,e,f,g,a,b,c,d,j,k,j]
and I want to search for the sequence abc and getting the index returned. So to clarify if the string I want to search consists of more than one element of the list. For some context: I have a list with datablocks and I want to find out how big each datablock is therefore searching for a reoccuring string in the list.
There are many good string search algorithms: KMP, Boyer-Moore, Rabin-Karp. You can use the builtin str.index function on ''.join(L) if you are dealing with characters (str.index implements Boyer-Moore algorithm in CPython: https://github.com/python/cpython/blob/3.7/Objects/stringlib/fastsearch.h).
But in most cases, the naive algorithm is good enough. Check every index of the haystack to find the needle:
>>> a, b, c, d, e, f, g, j, k = [object() for _ in range(9)]
>>> haystack = [a, b, c, d, e, f, g, a, b, c, d, j, k, j]
>>> needle = [a, b, c]
>>> for i in range(len(haystack)-len(needle)+1):
... if haystack[i:i+len(needle)] == needle:
... print(i)
...
0
7
The complexity is O(|haystack|*|needle|).
Let's say I want to create an object where some members aren't always present
t = {a: 1, b: b if b}
console.log t # { a: 1, b: undefined }
I'm trying to achieve this result when b is missing
t = {a: 1}
if b then t.b = b
console.log t # { a: 1 }
Is there a way I can declare b conditionally without creating the key, and without having a separate line of code?
When you need to do it repeatedly on a large object, you could do
t = Object.fromEntries(Object.entries(
a: 1
b: b
c: 2
).filter(e=>e[1]))
This would filter out the b property if b is falsey.