Comment #0 by bearophile_hugs — 2011-01-20T04:06:22Z
I use D associative arrays often so I'd like AAs to be modified so byKey() and byValue() return ranges (that have a length attribute too) usable with higher order functions of std.algorithm like map and filter.
AAs too may become iterable with no method calls:
map!q{a * 10}([1:2, 3:4])
I also suggest to add a third associative array member function that returns a range of (key,value) typecons tuples, as in a similar Python3 dict method.
------------------
To test the situation, this task is to create a dynamic array of pairs (tuples) like:
[(10,"aa"), (20,"bb"), (30,"cc")]
from the associative array:
[1:'a', 2:'b', 3:'c']
If possible reading things lazily from the associative array.
Idiomatic Python2 solution (iteritems is lazy):
>>> d = {1:'a', 2:'b', 3:'c'}
>>> [(k*10, v*2) for k,v in d.iteritems()]
[(10, 'aa'), (20, 'bb'), (30, 'cc')]
D2 lazy solution without map():
import std.stdio, std.typecons;
void main() {
auto aa = [1:'a', 2:'b', 3:'c'];
Tuple!(int, string)[] r;
foreach (k, v; aa)
r ~= tuple(k*10, ""~v~v);
writeln(r);
}
The byPair() range allows to solve the task functionally ad lazily like this:
import std.stdio, std.typecons, std.algorithm;
void main() {
auto aa = [1:'a', 2:'b', 3:'c'];
auto r = map!q{ tuple(a[0]*10, a[1]~a[1]) }(aa.byPair());
writeln(r);
}
Comment #1 by bearophile_hugs — 2012-01-17T14:17:49Z
After the work done for issue 4607 this is missing still:
import std.stdio, std.typecons, std.algorithm;
void main() {
auto aa = [1:'a', 2:'b', 3:'c'];
auto r = map!q{ tuple(a[0]*10, a[1]~a[1]) }(aa.byPair());
writeln(r);
}
Also clarified the title of this issue.
Comment #2 by bearophile_hugs — 2012-01-17T16:12:06Z
A comment by Andrei Alexandrescu:
> byPair is tricky because std.tuple is not visible from object.
Comment #3 by bearophile_hugs — 2012-02-29T14:18:53Z
This example shows an use case of byItem. Given a string, the task here is to show the char frequencies, putting higher frequencies on top, and sorting alphabetically the chars that share the same frequency.
A Python 2.6 program that solves the problem:
from collections import defaultdict
text = "the d programming language is an object oriented " + \
"imperative multi paradigm system programming " + \
"language created by walter bright of digital mars"
frequences = defaultdict(int)
for c in text:
frequences[c] += 1
pairs = sorted(frequences.iteritems(), key=lambda (c,f): (-f,c))
for (c, f) in pairs:
print f, c
The output of the Python program:
20
14 a
12 e
11 g
11 i
11 r
10 t
9 m
6 n
5 d
5 l
5 o
4 p
4 s
3 b
3 u
2 c
2 h
2 y
1 f
1 j
1 v
1 w
Three different solutions in D (probably there are other solutions, maybe even better ones) using Phobos:
import std.stdio, std.typecons, std.algorithm, std.array;
void main() {
auto text = "the d programming language is an object oriented " ~
"imperative multi paradigm system programming " ~
"language created by walter bright of digital mars";
int[char] frequences;
foreach (char c; text)
frequences[c]++;
Tuple!(int,char)[] pairs1 = array(map!(c => tuple(frequences[c], c))(frequences.byKey));
schwartzSort!(p => tuple(-p[0], p[1]))(pairs1);
foreach (pair; pairs1)
writeln(pair[0], " ", pair[1]);
writeln();
import std.conv;
dchar[] keys = to!(dchar[])(frequences.keys);
schwartzSort!(c => tuple(-frequences[cast(char)c], c))(keys);
foreach (dchar c; keys)
writeln(frequences[cast(char)c], " ", c);
writeln();
Tuple!(int,char)[] pairs1b = array(map!(c => tuple(-frequences[c], c))(frequences.byKey));
sort(pairs1b);
foreach (pair; pairs1b)
writeln(-pair[0], " ", pair[1]);
writeln();
}
A version using AA.byPair (or AA.pairs) (I have not used 'auto' for type clarity):
Tuple!(char,int)[] pairs2 = array(frequences.byPair);
schwartzSort!(c_f => tuple(-c_f[1], c_f[0]))(pairs2);
foreach (c_f; pairs2)
writeln(c_f[1], " ", c_f[0]);
With the eager AA.pairs and tuple unpacking syntax too:
Tuple!(char,int)[] pairs3 = frequences.pairs;
schwartzSort!(tuple(c,f) => tuple(-f, c))(pairs3);
foreach ((c, f); pairs3)
writeln(f, " ", c);
With AA.byPair, tuple unpacking syntax and schwartzSorted, this is approaching the Python version:
Tuple!(char,int)[] pairs4 = schwartzSorted!(tuple(c,f) => tuple(-f, c))(frequences.byPair);
foreach ((c, f); pairs4)
writeln(f, " ", c);
Comment #4 by bearophile_hugs — 2012-07-30T09:36:03Z
See also Issue 8473
Comment #5 by bearophile_hugs — 2013-12-16T15:25:09Z
See also the very similar Issue 11753
Comment #6 by andrei — 2013-12-16T15:58:51Z
*** Issue 11753 has been marked as a duplicate of this issue. ***