digitalmars.D.learn - Simplest way to create an array from an associative array which its
- Gary Willoughby (9/9) Jan 03 2014 Simplest way to create an array from an associative array which
- bearophile (14/23) Jan 03 2014 Unfortunately the D associative arrays specs don't specify this
- Andrej Mitrovic (4/5) Jan 03 2014 However the [k, aa[k]] expression will allocate an array for each
- bearophile (6/9) Jan 05 2014 Perhaps the "s" suffix (to define fixed-sized arrays) could avoid
- Andrej Mitrovic (7/10) Jan 05 2014 I would prefer a prefix though, to make it immediately obvious you're
- bearophile (4/5) Jan 09 2014 Do you remember the bug report number and/or pull request number
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (90/93) Jan 03 2014 I still like that solution. :) Even if it's not spelled out to be
- bearophile (8/13) Jan 03 2014 But in the long term ignoring what's present or missing in the
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (7/19) Jan 03 2014 I don't mean to ignore. I would like to see the spec changed. This feels...
- H. S. Teoh (8/23) Jan 03 2014 [...]
- bearophile (4/7) Jan 03 2014 A byPair will be needed in Phobos, in one way or another.
- Philippe Sigaud (19/22) Jan 05 2014 Is there any plan to add indexing on runtime indices to Tuple? It can
- Timon Gehr (2/5) Jan 05 2014 It would override the current index operator.
- Philippe Sigaud (2/8) Jan 05 2014 Yes, indeed.
- Andrej Mitrovic (15/17) Jan 03 2014 ----
- Justin Whear (2/22) Jan 03 2014 `only` is available in 2.063, maybe even earlier.
- Craig Dillabaugh (16/25) Jan 07 2014 As someone with little experience with functional programming, I
- H. S. Teoh (22/42) Jan 07 2014 [...]
- Craig Dillabaugh (15/59) Jan 07 2014 Yes, I would imagine if this was not a 'one off' operation, you
- Andrej Mitrovic (9/19) Jan 07 2014 OP asked for an array, however the reason I showed the example is
- Jakob Ovrum (9/16) Jan 07 2014 Assuming the return value of `byKey` has a length property, using
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?
Jan 03 2014
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
Jan 03 2014
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. :)
Jan 03 2014
Andrej Mitrovic: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. :)Perhaps the "s" suffix (to define fixed-sized arrays) could avoid that problem: string[] r = aa.byKey.map!(k => [k, aa[k]]s).join; Bye, bearophile
Jan 05 2014
On 1/5/14, bearophile <bearophileHUGS lycos.com> wrote:Perhaps the "s" suffix (to define fixed-sized arrays) could avoid that problem: string[] r = aa.byKey.map!(k => [k, aa[k]]s).join;I would prefer a prefix though, to make it immediately obvious you're creating a static array. string[] r = aa.byKey.map!(k => s[k, aa[k]]).join; It's not too bad.. But then again maybe tuples (and some syntax support) is the right solution for this.
Jan 05 2014
string[] r = aa.byKey.map!(k => [k, aa[k]]s).join;Do you remember the bug report number and/or pull request number for that enhancement? Bye, bearophile
Jan 09 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
Jan 03 2014
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
Jan 03 2014
On 01/03/2014 04:39 PM, bearophile wrote:Ali Çehreli: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 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.They make sense to me. AliI 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
Jan 03 2014
On Sat, Jan 04, 2014 at 12:39:32AM +0000, bearophile wrote:Ali Çehreli:[...] 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.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
Jan 03 2014
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
Jan 03 2014
On Sat, Jan 4, 2014 at 1:08 AM, Ali Çehreli <acehreli yahoo.com> wrote: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].Is there any plan to add indexing on runtime indices to Tuple? It can be done, by generating a specific runtime opIndex for Tuple, if the types held in the tuple have a common type. CommonType!Types opIndex(size_t index) { // generated code, say Types is 3-element long: switch(index) { case 0: return values[0]; case 1: return values[1]; case 2: return values[2]; default: throw new OutOfRangeException(...); } }
Jan 05 2014
On 01/05/2014 03:55 PM, Philippe Sigaud wrote:Is there any plan to add indexing on runtime indices to Tuple? It can be done, by generating a specific runtime opIndex for Tuple, if the types held in the tuple have a common type.It would override the current index operator.
Jan 05 2014
On Sun, Jan 5, 2014 at 4:49 PM, Timon Gehr <timon.gehr gmx.ch> wrote:On 01/05/2014 03:55 PM, Philippe Sigaud wrote:Yes, indeed.Is there any plan to add indexing on runtime indices to Tuple? It can be done, by generating a specific runtime opIndex for Tuple, if the types held in the tuple have a common type.It would override the current index operator.
Jan 05 2014
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.
Jan 03 2014
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:`only` is available in 2.063, maybe even earlier.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.
Jan 03 2014
On Friday, 3 January 2014 at 17:38:16 UTC, Gary Willoughby wrote: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?As someone with little experience with functional programming, I am just curious - having browsed through the thread - if the various solutions proposed here would really be considered more 'idiomatic' D. Or if they were posted because the OP asked about avoiding the foreach() loop. In other words while: auto range = aa.byKey.map!(a => chain(a.only, aa[a].only)); string[] array = range.join; Saves a few lines of code, and looks cooler, it seems that the trivial foreach loop version is very easy: string[] array; foreach (key, value; aa) { array ~= key; array ~= value; }
Jan 07 2014
On Tue, Jan 07, 2014 at 08:38:10PM +0000, Craig Dillabaugh wrote: [...]As someone with little experience with functional programming, I am just curious - having browsed through the thread - if the various solutions proposed here would really be considered more 'idiomatic' D. Or if they were posted because the OP asked about avoiding the foreach() loop. In other words while: auto range = aa.byKey.map!(a => chain(a.only, aa[a].only)); string[] array = range.join; Saves a few lines of code, and looks cooler, it seems that the trivial foreach loop version is very easy: string[] array; foreach (key, value; aa) { array ~= key; array ~= value; }[...] Even better, encapsulate this in a function: CommonType!(K,V)[] aaToArray(K,V)(V[K] aa) if (is(CommonType!(V, K))) { typeof(return) result; foreach (key, value; aa) { result ~= key; result ~= value; } return result; } Then you can use it in a single line next time: string[] arr = aaToArray(["a": "aa", "b" : "bb"]); int[] arr = aaToArray([1: 2, 3: 4]); ... // etc. T -- Real men don't take backups. They put their source on a public FTP-server and let the world mirror it. -- Linus Torvalds
Jan 07 2014
On Tuesday, 7 January 2014 at 20:52:40 UTC, H. S. Teoh wrote:On Tue, Jan 07, 2014 at 08:38:10PM +0000, Craig Dillabaugh wrote: [...]Yes, I would imagine if this was not a 'one off' operation, you would likely want to create a function. That one looks nice. I posted my question mainly because D advertises itself as a 'multi-paradigm' language. It seems that a number of the more experienced posters on here seem to like functional approaches using the algorithms in std.algorithm. However, it seems to me sometimes the obvious/simple solution that avoids using std.algorithm results in more readable code. So I was curious to know if using std.algorithm functions are generally considered preferable for simple cases like this, or if it is simply a matter of taste. As an aside, the trade-off is even more blatant in C++ where a simple hand-rolled solution often comes out looking so much nicer than the STL <algorithm> alternative.As someone with little experience with functional programming, I am just curious - having browsed through the thread - if the various solutions proposed here would really be considered more 'idiomatic' D. Or if they were posted because the OP asked about avoiding the foreach() loop. In other words while: auto range = aa.byKey.map!(a => chain(a.only, aa[a].only)); string[] array = range.join; Saves a few lines of code, and looks cooler, it seems that the trivial foreach loop version is very easy: string[] array; foreach (key, value; aa) { array ~= key; array ~= value; }[...] Even better, encapsulate this in a function: CommonType!(K,V)[] aaToArray(K,V)(V[K] aa) if (is(CommonType!(V, K))) { typeof(return) result; foreach (key, value; aa) { result ~= key; result ~= value; } return result; } Then you can use it in a single line next time: string[] arr = aaToArray(["a": "aa", "b" : "bb"]); int[] arr = aaToArray([1: 2, 3: 4]); ... // etc. T
Jan 07 2014
On 1/7/14, Craig Dillabaugh <cdillaba cg.scs.carleton.ca> wrote:In other words while: auto range = aa.byKey.map!(a => chain(a.only, aa[a].only)); string[] array = range.join; Saves a few lines of code, and looks cooler, it seems that the trivial foreach loop version is very easy: string[] array; foreach (key, value; aa) { array ~= key; array ~= value; }OP asked for an array, however the reason I showed the example is because you can get a range that way, which is lazy and will not allocate: auto items = aa.byKey.map!(a => chain(a.only, aa[a].only)).joiner; // no allocations at all writeln(items); So there's a huge difference, as you're saving memory (and CPU time if you don't want to walk through the entire list).
Jan 07 2014
On Tuesday, 7 January 2014 at 20:38:11 UTC, Craig Dillabaugh wrote:Saves a few lines of code, and looks cooler, it seems that the trivial foreach loop version is very easy: string[] array; foreach (key, value; aa) { array ~= key; array ~= value; }Assuming the return value of `byKey` has a length property, using std.array.array has the benefit of automatically allocating just once for the result, while your proposed alternative will grow on demand, causing several allocations that depend on the number of pairs in `aa`. Of course, Teoh's `aaToArray` can trivially do this too, but the naive loop straight in user code is just that - naive.
Jan 07 2014