Simplest way to create an array from an associative array which its contains keys and values?
Ali Çehreli
acehreli at yahoo.com
Fri Jan 3 16:08:36 PST 2014
On 01/03/2014 09:47 AM, bearophile wrote:
> Unfortunately the D associative arrays specs don't specify this to be
> correct:
>
> zip(aa.byKey, aa.byValue)
I still like that solution. :) Even if it's not spelled out to be
correct in the spec, I can't imagine a hash table implementation where
byKey and byValue don't iterate in lock step.
I wrote the following Expander range as an exercise. I think it could be
useful in Phobos. (I am aware that there are proposals to revamp tuples
in Phobos; the following is for 2.064.)
Some issues:
1) Yes, expand may not be the best name as it would be confusing with
Tuple.expand, which is a different thing.
2) As with some other InputRanges, the need to call the prime() member
function up front in the constructor feels weird. It makes the range
one-step eager. However, doing it in the front() conditionaly via 'if
(is_primed)' would bring a cost to every call to front().
3) The member rangeFront is needed because Tuple does not have opIndex
for dynamic indexes. I can do range.front[0] but I cannot do
range.front[currentIndex]. So, my solution was to take advantage of
Tuple.expand by wrapping it in a slice, which I have taken out due to
performance concern, without ever measuring anything. :p
import std.range;
void main()
{
auto aa = ["one":"1", "two":"2"];
assert(zip(aa.byKey, aa.byValue)
.expand
.equal([ "one", "1", "two", "2" ]));
}
/* Expands individual members of elements of a tuple-range as elements
* of this range. */
struct Expander(R)
if (__traits(compiles, [ ElementType!R ]))
{
alias ElementT = typeof([ ElementType!R.expand ].front);
R range;
ElementT[ElementType!R.length] rangeFront;
size_t currentIndex;
this(R range)
{
this.range = range;
prime();
}
private void prime()
{
if (!empty) {
currentIndex = 0;
/* The following static foreach "I think" avoids a dynamic
array
* allocation when compared to the following line:
*
* rangeFront = [ range.front.expand ];
*/
foreach (i, element; range.front) {
rangeFront[i] = element;
}
}
}
bool empty() @property
{
return range.empty;
}
ElementT front() @property
{
return rangeFront[currentIndex];
}
void popFront()
{
++currentIndex;
if (currentIndex == ElementType!R.length) {
range.popFront();
prime();
}
}
}
Expander!R expand(R)(R range)
if (__traits(compiles, [ ElementType!R ]))
{
return Expander!R(range);
}
unittest
{
import std.typecons;
auto a = [ tuple(1, 2.2), tuple(3, 4.4) ];
auto expanded = a.expand;
static assert(is (typeof(expanded.front) == double));
assert(expanded.equal([ 1, 2.2, 3, 4.4 ]));
// Incompatible tuple members should fail to compile
auto mismatched = [ tuple(int.init, string.init) ];
static assert(!__traits(compiles, mismatched.expand));
}
Ali
More information about the Digitalmars-d-learn
mailing list