Thread overview | |||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
January 03, 2014 Simplest way to create an array from an associative array which its contains keys and values? | ||||
---|---|---|---|---|
| ||||
Simplest way to create an array from an associative array which its contains keys and values? For example if i have an associative array like this: ["one":"1", "two":"2"] What's the easiest way to create a dynamic array that looks like this: ["one", "1", "two", "2"] I know it can be done via a loop, but is there a more idiomatic way to achieve this? |
January 03, 2014 Re: Simplest way to create an array from an associative array which its contains keys and values? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Gary Willoughby | Gary Willoughby:
> Simplest way to create an array from an associative array which its contains keys and values?
>
> For example if i have an associative array like this:
>
> ["one":"1", "two":"2"]
>
> What's the easiest way to create a dynamic array that looks like this:
>
> ["one", "1", "two", "2"]
>
> I know it can be done via a loop, but is there a more idiomatic way to achieve this?
Unfortunately the D associative arrays specs don't specify this to be correct:
zip(aa.byKey, aa.byValue)
So a solution without foreach loops is:
void main() {
import std.stdio, std.algorithm, std.array;
auto aa = ["one":"1", "two":"2"];
string[] r = aa.byKey.map!(k => [k, aa[k]]).join;
r.writeln;
}
You can also use joiner if you need just a lazy range.
Bye,
bearophile
|
January 03, 2014 Re: Simplest way to create an array from an associative array which its contains keys and values? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Gary Willoughby | On Friday, 3 January 2014 at 17:38:16 UTC, Gary Willoughby wrote:
> I know it can be done via a loop, but is there a more idiomatic way to achieve this?
----
import std.algorithm;
import std.range;
import std.stdio;
void main()
{
auto aa = ["one":"1", "two":"2"];
auto range = aa.byKey.map!(a => chain(a.only, aa[a].only));
string[] array = range.join;
writeln(array);
}
----
However I'm not sure whether "only" is present in 2.064, maybe it was added recently in the git-head version.
|
January 03, 2014 Re: Simplest way to create an array from an associative array which its contains keys and values? | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On Friday, 3 January 2014 at 17:47:43 UTC, bearophile wrote:
> string[] r = aa.byKey.map!(k => [k, aa[k]]).join;
However the [k, aa[k]] expression will allocate an array for each key you iterate over regardless if you use join or joiner. I posted a solution with "only", hope that works. :)
|
January 03, 2014 Re: Simplest way to create an array from an associative array which its contains keys and values? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrej Mitrovic | On Fri, 03 Jan 2014 17:49:28 +0000, Andrej Mitrovic wrote:
> On Friday, 3 January 2014 at 17:38:16 UTC, Gary Willoughby wrote:
>> I know it can be done via a loop, but is there a more idiomatic way to achieve this?
>
> ----
> import std.algorithm;
> import std.range;
> import std.stdio;
>
> void main()
> {
> auto aa = ["one":"1", "two":"2"];
> auto range = aa.byKey.map!(a => chain(a.only, aa[a].only));
> string[] array = range.join;
> writeln(array);
> }
> ----
>
> However I'm not sure whether "only" is present in 2.064, maybe it was added recently in the git-head version.
`only` is available in 2.063, maybe even earlier.
|
January 04, 2014 Re: Simplest way to create an array from an associative array which its contains keys and values? | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | 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 |
January 04, 2014 Re: Simplest way to create an array from an associative array which its contains keys and values? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | Ali Çehreli: > 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. But in the long term ignoring what's present or missing in the specs is a bad idea. > I wrote the following Expander range as an exercise. See also: https://d.puremagic.com/issues/show_bug.cgi?id=5489 https://d.puremagic.com/issues/show_bug.cgi?id=7957 Bye, bearophile |
January 04, 2014 Re: Simplest way to create an array from an associative array which its contains keys and values? | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On 01/03/2014 04:39 PM, bearophile wrote: > Ali Çehreli: > >> 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. > > But in the long term ignoring what's present or missing in the specs is > a bad idea. I don't mean to ignore. I would like to see the spec changed. This feels similar to first C++ standard never explicitly requiring that the elements of a string be contiguous in memory but every implementation doing so. >> I wrote the following Expander range as an exercise. > > See also: > https://d.puremagic.com/issues/show_bug.cgi?id=5489 > https://d.puremagic.com/issues/show_bug.cgi?id=7957 > > Bye, > bearophile They make sense to me. Ali |
January 04, 2014 Re: Simplest way to create an array from an associative array which its contains keys and values? | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On Sat, Jan 04, 2014 at 12:39:32AM +0000, bearophile wrote: > Ali Çehreli: > > >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. > > But in the long term ignoring what's present or missing in the specs is a bad idea. > > > >I wrote the following Expander range as an exercise. > > See also: https://d.puremagic.com/issues/show_bug.cgi?id=5489 https://d.puremagic.com/issues/show_bug.cgi?id=7957 [...] I did an implementation of aa.byPair once, that iterates over keys and values simultaneously, but it was ultimately rejected: https://github.com/D-Programming-Language/druntime/pull/574 T -- What's a "hot crossed bun"? An angry rabbit. |
January 04, 2014 Re: Simplest way to create an array from an associative array which its contains keys and values? | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | H. S. Teoh:
> I did an implementation of aa.byPair once, that iterates over keys and
> values simultaneously, but it was ultimately rejected:
A byPair will be needed in Phobos, in one way or another.
Bye,
bearophile
|
Copyright © 1999-2021 by the D Language Foundation