Re: Sort Associative Array by Key

2023-02-09 Thread Ali Çehreli via Digitalmars-d-learn

On 2/8/23 23:19, Alexander Zhirov wrote:
>> foo.byPair
>>  .array
>>  .sort!((a, b) => a.key < b.key)
>>  .map!(a => a.value);
>
> Is it possible to specify in `map` to return the result `[a.key] =
> a.value`? To make the result look like `[key:[val], key:[val]]`

map can return a tuple and std.array.assocArray can make an associative 
array from those tuples:


import std;

void main() {
auto aa = iota(10)
  .map!(n => tuple(n, n * n))
  .assocArray;
writeln("Necessarily unsorted:\n", aa);
}

However, as the original question started with an associative array 
anyway, I don't think I understand your question correctly. :)


If you are asking whether an associative array can store in sorted key 
order, then no, it's impossible because associative arrays are hash 
tables, which can't provide that.


But we can visit the elements in sorted order if we sort those keys 
ourselves:


auto keys = aa
.keys  // <- Makes an array by copying the keys
.sort;

writeln("In order:");
foreach (k; keys) {
writeln(k, ": ", aa[k]);
}

Ali



Re: Sort Associative Array by Key

2023-02-09 Thread ProtectAndHide via Digitalmars-d-learn
On Thursday, 9 February 2023 at 07:19:08 UTC, Alexander Zhirov 
wrote:

foo.byPair
 .array
 .sort!((a, b) => a.key < b.key)
 .map!(a => a.value);


Is it possible to specify in `map` to return the result 
`[a.key] = a.value`? To make the result look like `[key:[val], 
key:[val]]`


Wow. This is an old thread

.. anyway... how about making custom strings out of the KV pairs:

void main()
{
import std.conv : to;
import std.algorithm : sort;
import std.stdio : writeln;

auto foo = ["VXE":8, "BZP":5, "JLC":2];

string[] orderedKeyPairSet;

foreach (ref kv; foo.byKeyValue)
{
orderedKeyPairSet ~= kv.key.to!string ~ ":" ~ 
kv.value.to!string;


}

orderedKeyPairSet.sort;

foreach(ref str; orderedKeyPairSet)
writeln(str);

}

/*
output:

BZP:5
JLC:2
VXE:8

*/



Re: Sort Associative Array by Key

2023-02-08 Thread Alexander Zhirov via Digitalmars-d-learn

foo.byPair
 .array
 .sort!((a, b) => a.key < b.key)
 .map!(a => a.value);


Is it possible to specify in `map` to return the result `[a.key] 
= a.value`? To make the result look like `[key:[val], key:[val]]`


Re: Sort Associative Array by Key

2019-08-28 Thread a11e99z via Digitalmars-d-learn

On Tuesday, 27 August 2019 at 20:35:16 UTC, bachmeier wrote:

On Tuesday, 27 August 2019 at 20:14:21 UTC, Machine Code wrote:


It isn't really hard:


It really is hard. foo.byPair.array.sort!((a, b) => a.key < 
b.key).map!(a => a.value); is a lot to digest for someone 
learning the language. There's a big difference between not 
being hard for someone that understands what each piece does 
and not being hard for someone new to D. At a minimum, it would 
help to write it


foo.byPair
 .array
 .sort!((a, b) => a.key < b.key)
 .map!(a => a.value);


I wrote expression with string lambdas for one purpose:
when u see very simple beauty thing that is working and u totally 
doesn't understand how exactly, ur curiosity should do the rest 
of the work. it's worth sorting out.

if man wanted just do his job, he got this too.


Re: Sort Associative Array by Key

2019-08-28 Thread berni via Digitalmars-d-learn

On Tuesday, 27 August 2019 at 16:25:00 UTC, Samir wrote:
As I've mentioned on the list before, I really struggle to 
understand how some of the std.algorithm functions such as 
`map` work when combined with things like `array`, `sort` and 
especially `zip` but really appreciate the support I find here 
on the forum.


A few months ago I stuggled with that too. Meanwhile I think I 
got it.


Let's examine just the first step in this sequence:


writeln(foo.byPair);


This leads to

[Tuple!(string, "key", int, "value")("BZP", 5), Tuple!(string, 
"key", int, "value")("VXE", 8), Tuple!(string, "key", int, 
"value")("JLC", 2)]


Well, this look like an array of tuples, each tuple containing a 
key and a value. I assume, that you understand tuples, I think, 
they are not the problem here. The problem arises, because the 
result of "foo.byPair" isn't an array. Actually writeln converts 
the result to an array, before printing it (or at least it 
pretends to do so). You can see this with:



writeln(typeof(foo.byPair).stringof);


Which is:


MapResult!(__lambda2, Result)


Ooops, what's that? Having a look at the documentation isn't very 
instructive (at least at beginners level):



auto byPair(AA)(AA aa)
if (isAssociativeArray!AA);


That's almost all you get. Almost, because the description 
mentions, that the return value is a forward range. Ah, it's a 
range. I'm not sure, how much you know about ranges. If you want 
to understand that stuff, you should study them. E.g. try to 
write some ranges of your own.


When thinking of a range, I imagine it as sort of a voucher for 
something like an array. You can use that voucher to get elements 
from that array. In case of an forward range, you are restricted 
to get the elements ony by one from the beginning. You get them 
by using the function front(), which all ranges provide. Let's 
try it:



auto something = foo.byPair;
writeln(something.front);


And we get:


Tuple!(string, "key", int, "value")("BZP", 5)


That's indeed the first of our elements. We don't know yet, what 
this range is doing behind the sceens. But I can tell you: When 
calling byPair it hasn't done much: It just signed that voucher 
and handed it out to you (that's called lazy evaluation, contrary 
to eager evaluation). Maybe you never use that voucher. In that 
case it would be wasted time to calculate all the elements, that 
are never used.


The moment you call front, that range starts to do some of the 
work. It assembles the first item of the range and hand's this 
out to you. Then it stops again - the other items are not yet 
calculated. That's done, when you call front again (but before 
you need to call popFront, to remove the first item, else you 
would get the item, you allready have, once again). And so on.


Now we know, how to use this range and that's what "array" does: 
It calls front and popFront as long as there are more elements 
(this can be checked by calling empty on the range), and puts 
them into an array. But what we don't understand yet is that 
strange type of the range: MapResult!(__lambda2, Result).


For that, we should have a look at the implementation (I'm using 
http://dpldocs.info/experimental-docs/std.array.byPair.html for 
that, because it has a link to the documentation at the bottom), 
we find out, that byPair is implemented using byKeyValue and map:



return aa.byKeyValue
   .map!(pair => tuple!("key", "value")(pair.key, 
pair.value));


byKeyValue is defined in object, which has no source code - I 
guess it's implemented directly in the compiler somehow. By using 
typeof, we find out that the type is "Result" and by using 
writeln we find out, that the result of byKeyValue looks like an 
array of Pairs of pointers. Again it's a range, that we can use 
like above.


This range (think again of a voucher) is now send to map. Map 
needs, beside this range, a function. You could write that 
function like:



auto make_tuple(Pair pair)
{
return tuple!("key", "value")(pair.key, pair.value);
}


Than the above could be written as


return aa.byKeyValue.map!(make_tuple);


Beside the fact, that I cannot find the definition of Pair (and 
therefore would need to make a template instead of the function), 
it's not necessary to write that function explicitly. There is a 
way, to write functions more compressed, namely by using =>, like 
it's done above. Those functions are called lambda-functions 
(because at some places a greek lambda symbol was used for the 
function parameter).


Now, map is lazy too. It just remembers that function, the 
"voucher" it got and hand's you an other voucher. That's all. 
This new voucher is called "MapResult", which is actually a 
struct with functions "front", "popFront" and "empty" (and some 
more, but we don't care). And this struct has two 
template-parameters, namely a function and a range. We know that 
range already, it's Result from byKeyValue. And that function, 
which has no name, got the name "__lambda2" from th

Re: Sort Associative Array by Key

2019-08-27 Thread bachmeier via Digitalmars-d-learn

On Tuesday, 27 August 2019 at 20:14:21 UTC, Machine Code wrote:


It isn't really hard:


It really is hard. foo.byPair.array.sort!((a, b) => a.key < 
b.key).map!(a => a.value); is a lot to digest for someone 
learning the language. There's a big difference between not being 
hard for someone that understands what each piece does and not 
being hard for someone new to D. At a minimum, it would help to 
write it


foo.byPair
 .array
 .sort!((a, b) => a.key < b.key)
 .map!(a => a.value);


Re: Sort Associative Array by Key

2019-08-27 Thread Machine Code via Digitalmars-d-learn

On Tuesday, 27 August 2019 at 16:25:00 UTC, Samir wrote:

On Sunday, 25 August 2019 at 17:01:23 UTC, a11e99z wrote:

auto foo = ["VXE":8, "BZP":5, "JLC":2];
foo.byPair.array.sort!"a[0]

On Sunday, 25 August 2019 at 19:03:10 UTC, JN wrote:

I think normal lambdas are better than these string ones:

foo.byPair.array.sort!((a, b) => a[0] < b[0]).map!(a => 
a[1]).writeln;


On Sunday, 25 August 2019 at 21:13:05 UTC, Paul Backus wrote:

You can also use names instead of numeric indices:

foo.byPair.array.sort!((a, b) => a.key < b.key).map!(a => 
a.value);


a11e99z, JN, Paul:  Thank you all for your replies and help.  
As I've mentioned on the list before, I really struggle to 
understand how some of the std.algorithm functions such as 
`map` work when combined with things like `array`, `sort` and 
especially `zip` but really appreciate the support I find here 
on the forum.


Samir


It isn't really hard:
.array() turns the range into an array, so that sort() can work.
sort() takes "callback" function to test the elements while 
sorting and determine the proper position in the array.
map() select the property from each element, putting that 
requested property into an array.




Re: Sort Associative Array by Key

2019-08-27 Thread Samir via Digitalmars-d-learn

On Sunday, 25 August 2019 at 17:01:23 UTC, a11e99z wrote:

auto foo = ["VXE":8, "BZP":5, "JLC":2];
foo.byPair.array.sort!"a[0]

On Sunday, 25 August 2019 at 19:03:10 UTC, JN wrote:

I think normal lambdas are better than these string ones:

foo.byPair.array.sort!((a, b) => a[0] < b[0]).map!(a => 
a[1]).writeln;


On Sunday, 25 August 2019 at 21:13:05 UTC, Paul Backus wrote:

You can also use names instead of numeric indices:

foo.byPair.array.sort!((a, b) => a.key < b.key).map!(a => 
a.value);


a11e99z, JN, Paul:  Thank you all for your replies and help.  As 
I've mentioned on the list before, I really struggle to 
understand how some of the std.algorithm functions such as `map` 
work when combined with things like `array`, `sort` and 
especially `zip` but really appreciate the support I find here on 
the forum.


Samir




Re: Sort Associative Array by Key

2019-08-25 Thread Paul Backus via Digitalmars-d-learn

On Sunday, 25 August 2019 at 19:03:10 UTC, JN wrote:

I think normal lambdas are better than these string ones:

foo.byPair.array.sort!((a, b) => a[0] < b[0]).map!(a => 
a[1]).writeln;


You can also use names instead of numeric indices:

foo.byPair.array.sort!((a, b) => a.key < b.key).map!(a => 
a.value);


Re: Sort Associative Array by Key

2019-08-25 Thread JN via Digitalmars-d-learn

On Sunday, 25 August 2019 at 17:01:23 UTC, a11e99z wrote:

On Sunday, 25 August 2019 at 16:54:33 UTC, Samir wrote:
Is there a way to output the values of an associative array 
based on the lexicographic order of the keys?


For example, if foo = ["VXE":8, "BZP":5, "JLC":2], I'd like to 
output something like:


5
2
8




auto foo = ["VXE":8, "BZP":5, "JLC":2];
foo.byPair.array.sort!"a[0]

I think normal lambdas are better than these string ones:

foo.byPair.array.sort!((a, b) => a[0] < b[0]).map!(a => 
a[1]).writeln;


Re: Sort Associative Array by Key

2019-08-25 Thread a11e99z via Digitalmars-d-learn

On Sunday, 25 August 2019 at 16:54:33 UTC, Samir wrote:
Is there a way to output the values of an associative array 
based on the lexicographic order of the keys?


For example, if foo = ["VXE":8, "BZP":5, "JLC":2], I'd like to 
output something like:


5
2
8




auto foo = ["VXE":8, "BZP":5, "JLC":2];
foo.byPair.array.sort!"a[0]




Re: sort associative array by key

2012-11-23 Thread Timon Gehr

On 11/23/2012 07:48 PM, dsmith wrote:

On Friday, 23 November 2012 at 18:24:07 UTC, Timon Gehr wrote:

On 11/23/2012 07:09 PM, dsmith wrote:

What is the best way to have a function sort an associative array by
key?  The following yields a conversion error.

double[string] aa_sort(double[string] aa) {
  return aa.keys.sort;
}




A hash table is unsorted by definition. What is it that you want to do
exactly?

The following will generate a newly allocated dynamic array of
key-value pairs, sorted by key:

import std.algorithm, std.typecons;

Tuple!(string, double)[] aa_sort(double[string] aa){
typeof(return) r=[];
foreach(k,v;aa) r~=tuple(k,v);
sort!q{a[0]

Suppose the string is of the format 201207, 21208, ...
So aa["201207"] == 123.45

How do you parse the tuple for the key and the value?


tpl[0] is the key and tpl[1] is the value in this case.


Re: sort associative array by key

2012-11-23 Thread dsmith

On Friday, 23 November 2012 at 18:24:07 UTC, Timon Gehr wrote:

On 11/23/2012 07:09 PM, dsmith wrote:
What is the best way to have a function sort an associative 
array by

key?  The following yields a conversion error.

double[string] aa_sort(double[string] aa) {
  return aa.keys.sort;
}




A hash table is unsorted by definition. What is it that you 
want to do exactly?


The following will generate a newly allocated dynamic array of 
key-value pairs, sorted by key:


import std.algorithm, std.typecons;

Tuple!(string, double)[] aa_sort(double[string] aa){
typeof(return) r=[];
foreach(k,v;aa) r~=tuple(k,v);
sort!q{a[0]

Suppose the string is of the format 201207, 21208, ...
So aa["201207"] == 123.45

How do you parse the tuple for the key and the value?


Re: sort associative array by key

2012-11-23 Thread Timon Gehr

On 11/23/2012 07:09 PM, dsmith wrote:

What is the best way to have a function sort an associative array by
key?  The following yields a conversion error.

double[string] aa_sort(double[string] aa) {
   return aa.keys.sort;
}




A hash table is unsorted by definition. What is it that you want to do 
exactly?


The following will generate a newly allocated dynamic array of key-value 
pairs, sorted by key:


import std.algorithm, std.typecons;

Tuple!(string, double)[] aa_sort(double[string] aa){
typeof(return) r=[];
foreach(k,v;aa) r~=tuple(k,v);
sort!q{a[0]

Re: sort associative array by key

2012-11-23 Thread Andrej Mitrovic
On 11/23/12, dsmith  wrote:
> What is the best way to have a function sort an associative array
> by key?  The following yields a conversion error.
>
> double[string] aa_sort(double[string] aa) {
>return aa.keys.sort;
> }

Hashes are unordered, you can't sort them by key because they don't
preserve any order during insertion/removal. You can alternatively
return a sorted array:

string[] keys_sorted(double[string] aa) {
string[] keys = aa.keys;
sort(keys);  // from std.algorithm;
return keys;
}