What is the equivalent of Scala groupBy in D? - d

Whenever you want to create a frequency Map in Scala, you can easily call .groupBy on a collection.
val seq = Seq("a", "a", "b", "c", "b", "a")
seq.groupBy(a => a) // Map(b -> List(b, b), a -> List(a, a, a), c -> List(c))
Same is easily done with nested collections.
val nseq = Seq(Seq("a", 1), Seq("a", -1), Seq("b", -5), Seq("c", 100), Seq("b", 5), Seq("a", 0))
nseq.groupBy(a => a(0)) // Map(b -> List(List(b, -5), List(b, 5)), a -> List(List(a, 1), List(a, -1), List(a, 0)), c -> List(List(c, 100)))
Notice how values get aggregated together for each key.
I tried to find analogous function in D and found group. It works somewhat differently since it returns tuple pairs.
int[] arr = [1, 1, 2, 2, 3, 2, 2, 5];
arr.sort.group; // [Tuple!(int, uint)(1, 2), Tuple!(int, uint)(2, 4), Tuple!(int, uint)(3, 1), Tuple!(int, uint)(5, 1)]
arr.sort.group.assocArray; // [5:1, 3:1, 2:4, 1:2]
However, when it comes to nested collections.
Tuple!(string, int)[] arr = [tuple("a", 1), tuple("a", -1), tuple("b", 2), tuple("b", 25), tuple("c", 100), tuple("b", 21)];
arr.sort!("a[0] > b[0]").group!((a, b) => a[0] == b[0]); //(Tuple!(string, int)("c", 100), 1), (Tuple!(string, int)("b", 25), 3), (Tuple!(string, int)("a", 1), 2)]
The value aggregation does not happen and only the first value is taken. But what's the use of taking just one first value? One can of course circumvent this via
int[][string] res;
arr.each!(s => res[s[0]] ~= [s[1]]);
writeln(res) // ["c":[100], "a":[1, -1], "b":[25, 2, 21]]
but is it possible to this in one line without predefining res array?

Tuple!(string, int)[] arr = [tuple("a", 1), tuple("a", -1), tuple("b", 2), tuple("b", 25), tuple("c", 100), tuple("b", 21)];
arr.sort!("a[0] > b[0]").group!((a, b) => a[0] == b[0]); // [Tuple!(string, int)("b", 25):3, Tuple!(string, int)("c", 100):1, Tuple!(string, int)("a", 1):2]
That's not the result I'm getting:
https://run.dlang.io/is/9lVPkv
It results in [tuple(tuple("c", 100), 1), tuple(tuple("b", 25), 3), tuple(tuple("a", 1), 2)], which looks correct.
but is it possible to this in one line without predefining res array?
I think you're looking for chunkBy:
arr.sort!("a[0] > b[0]").chunkBy!((a, b) => a[0] == b[0]).each!writeln;
This results in:
[Tuple!(string, int)("c", 100)]
[Tuple!(string, int)("b", 25), Tuple!(string, int)("b", 2), Tuple!(string, int)("b", 21)]
[Tuple!(string, int)("a", 1), Tuple!(string, int)("a", -1)]

Related

IntRange with flatten , map and flatmap kotlin

Hi im doing atomic kotlin manupulating lists exercise.I need to help understanding the following
val intRange = 1..3
intRange.map { a -> // [1]
intRange.map { b -> a to b }
} eq "[" +
"[(1, 1), (1, 2), (1, 3)], " +
"[(2, 1), (2, 2), (2, 3)], " +
"[(3, 1), (3, 2), (3, 3)]" +
"]"
where do a , b values come from ?
We have that val intRange = 1..3 :
This is an IntRange from 1 to 3 (both inclusive)
Then we have the first map: intRange.map { a -> ... }
This map is going to loop through the intRange and it takes a lambda function as a parameter which is this in your case { a -> ... }, a will take each time the value of the current Int from the IntRange, so this lambda function is going to get executed 3 times with a having 3 different values (1, 2, 3), and you can call that a anything else you want so your function could be like that for example:
intRange.map { myValue ->
println(myValue) // 1, 2, 3
}
and you can even delete myValue -> and the variable name will be it which is the default name:
intRange.map {
println(it) // 1, 2, 3
}
and the same thing for b, a and b are going to take their values from that intRange, they will start from 1 to 3 (1, 2, 3) because the intRange = 1..3, if you change it to this val intRange = 1..4, then a and b are going to start from 1 to 4.

How to sort a List of Lists of pairs of number in descending order by the second item in each pair in Scala?

I have a list that looks like this List(List(0, 2), List(0, 3), List(2, 3), List(3, 2), List(3, 0), List(2, 0))), note this list will only contain pairs and will not contain duplicate pairs. I want to sort the list in descending order by the second item in each sub list in this larger list. If there are duplicate values I don't really which comes first.
For this instance the answer could look like List(List(0,3), List(2,3), List(0,2), List(3,2), List(3,0), List(2,0))
My idea was looping through the larger list and get a list containing each second item in each pair and sort those but I am having trouble keeping track of which second item in each pair belong to which pair afterwards. Perhaps there is a more clever way?
A simple solution would be:
list.sortBy(-_.last)
You can simply do:
list.sortBy(-_(1))
If the lists are always length 2, I would use tuples instead of lists. Then it is just a matter of using sortBy
scala> val l1 = List(List(0, 2), List(0, 3), List(2, 3), List(3, 2), List(3, 0), List(2, 0))
l1: List[List[Int]] = List(List(0, 2), List(0, 3), List(2, 3), List(3, 2), List(3, 0), List(2, 0))
scala> val l2 = l1.map(x => (x(0), x(1)))
l2: List[(Int, Int)] = List((0,2), (0,3), (2,3), (3,2), (3,0), (2,0))
scala> l2.sortBy(-_._2)
res1: List[(Int, Int)] = List((0,3), (2,3), (0,2), (3,2), (3,0), (2,0))
list.sortBy( sublist => -1 * sublist.tail.head )

Replacing the values of `edgelist` with those of a `labels` dictionary

I am new to both Python and NetworkX. I have a square, regular graph G with NxN nodes (a lattice). Such nodes are labelled by means of a dict (see code below). Now I want the edgelist to return the start and endpoint of each edge not by referring to the node coordinates but to the label the node has been given.
Example:
N = 3
G=nx.grid_2d_graph(N,N)
labels = dict( ((i, j), i + (N-1-j) * N ) for i, j in G.nodes() )
#This gives nodes an attribute ID that is identical to their labels
for (i,j) in labels:
G.node[(i,j)] ['ID']= labels[(i,j)]
edgelist=G.edges() #This gives the list of all edges in the format (Start XY, End XY)
If I run it with N=3 I get:
In [14]: labels
Out[14]: {(0, 0): 6, (0, 1): 3, (0, 2): 0, (1, 0): 7, (1, 1): 4, (1, 2): 1, (2, 0): 8, (2, 1): 5, (2, 2): 2}
This scheme labels the upper left node as 0, with node (N-1)th being placed in the lower right corner. And this is what I want. Now the problem with edgelist:
In [15]: edgelist
Out [15]: [((0, 1), (0, 0)), ((0, 1), (1, 1)), ((0, 1), (0, 2)), ((1, 2), (1, 1)), ((1, 2), (0, 2)), ((1, 2), (2, 2)), ((0, 0), (1, 0)), ((2, 1), (2, 0)), ((2, 1), (1, 1)), ((2, 1), (2, 2)), ((1, 1), (1, 0)), ((2, 0), (1, 0))]
I tried to solve the problem with these lines (inspiration from here: Replace items in a list using a dictionary):
allKeys = {}
for subdict in (labels):
allKeys.update(subdict)
new_edgelist = [allKeys[edge] for edge in edgelist]
but I get this wonderful thing which enlightens my monday:
TypeError: cannot convert dictionary update sequence element #0 to a sequence
To sum up, I want to be able to replace the elements of the edgelist list with the values of the labels dictionary so that, say, the edge from ((2,0),(1,0)) (which correspond to nodes 8 and 7) is returned (8,7). Endless thanks!
I believe what you are looking for is simply nx.relabel_nodes(G,labels,False) here is the documentation
Here is the output when I printed the nodes of G before and after calling the relabel nodes function.
# Before relabel_nodes
[(0, 1), (1, 0), (0, 0), (1, 1)]
# After relabel_nodes
[0, 1, 2, 3]
After doing this, the edge labels automatically becomes what you expect.
# Edges before relabelling nodes
[((0, 1), (0, 0)), ((0, 1), (1, 1)), ((1, 0), (0, 0)), ((1, 0), (1, 1))]
# Edges after relabelling nodes
[(0, 1), (0, 2), (1, 3), (2, 3)]
Also, I have replied to this question in the chat that you created but it seems you were not notified.

Composing a list of all pairs

I'm brand new to Scala, having had very limited experience with functional programming through Haskell.
I'd like to try composing a list of all possible pairs constructed from a single input list. Example:
val nums = List[Int](1, 2, 3, 4, 5) // Create an input list
val pairs = composePairs(nums) // Function I'd like to create
// pairs == List[Int, Int]((1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (2, 1) ... etc)
I tried using zip on each element with the whole list, hoping that it would duplicate the one item across the whole. It didn't work (only matched the first possible pair). I'm not sure how to repeat an element (Haskell does it with cycle and take I believe), and I've had trouble following the documentation on Scala.
This leaves me thinking that there's probably a more concise, functional way to get the results I want. Does anybody have a good solution?
How about this:
val pairs = for(x <- nums; y <- nums) yield (x, y)
For those of you who don't want duplicates:
val uniquePairs = for {
(x, idxX) <- nums.zipWithIndex
(y, idxY) <- nums.zipWithIndex
if idxX < idxY
} yield (x, y)
val nums = List(1,2,3,4,5)
uniquePairs: List[(Int, Int)] = List((1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5), (3, 4), (3, 5), (4, 5))
Here's another version using map and flatten
val pairs = nums.flatMap(x => nums.map(y => (x,y)))
List[(Int, Int)] = List((1,1), (1,2), (1,3), (1,4), (1,5), (2,1), (2,2), (2,3), (2,4), (2,5), (3,1), (3,2), (3,3), (3,4), (3,5), (4,1), (4,2), (4,3), (4,4), (4,5), (5,1), (5,2) (5,3), (5,4), (5,5))
This can then be easily wrapped into a composePairs function if you like:
def composePairs(nums: Seq[Int]) =
nums.flatMap(x => nums.map(y => (x,y)))

What's the most Pythonic way to identify consecutive duplicates in a list?

I've got a list of integers and I want to be able to identify contiguous blocks of duplicates: that is, I want to produce an order-preserving list of duples where each duples contains (int_in_question, number of occurrences).
For example, if I have a list like:
[0, 0, 0, 3, 3, 2, 5, 2, 6, 6]
I want the result to be:
[(0, 3), (3, 2), (2, 1), (5, 1), (2, 1), (6, 2)]
I have a fairly simple way of doing this with a for-loop, a temp, and a counter:
result_list = []
current = source_list[0]
count = 0
for value in source_list:
if value == current:
count += 1
else:
result_list.append((current, count))
current = value
count = 1
result_list.append((current, count))
But I really like python's functional programming idioms, and I'd like to be able to do this with a simple generator expression. However I find it difficult to keep sub-counts when working with generators. I have a feeling a two-step process might get me there, but for now I'm stumped.
Is there a particularly elegant/pythonic way to do this, especially with generators?
>>> from itertools import groupby
>>> L = [0, 0, 0, 3, 3, 2, 5, 2, 6, 6]
>>> grouped_L = [(k, sum(1 for i in g)) for k,g in groupby(L)]
>>> # Or (k, len(list(g))), but that creates an intermediate list
>>> grouped_L
[(0, 3), (3, 2), (2, 1), (5, 1), (2, 1), (6, 2)]
Batteries included, as they say.
Suggestion for using sum and generator expression from JBernardo; see comment.