www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Splitting a range into a range of tuples

reply "Adam" <stiff example.com> writes:
Hi,

I have a string of pairs of integers, where pairs are delimited 
from each other by commas, and members of the pair are delimited 
by a space. I'd like to end up with something like a range of 
2-tuples, which I can then sort with a lambda. I'm running into 
problems trying to do this, after splitting on commas:

Tuple!(int,int) coord = to!(int[])(splitter(pairString," 
").array[]);

...which may not even be a good idea, I don't know. I've been 
following D for a long time, but this is the first time I've 
tried to actually use it; this seems like the kind of thing that 
should take just a few lines, if only I knew the libraries and 
range concepts well enough.

To be clear, this is what I have:

"192 14, 301 3, 578 0, 0 17"

...and this is what I want:

[(578,0),(301,3),(192,14),(0,17)]

What's the best way to do this? Should I be using map!() 
somewhere?

Thanks,
Adam
Jun 01 2015
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 06/01/2015 03:31 PM, Adam wrote:
 Hi,

 I have a string of pairs of integers, where pairs are delimited from
 each other by commas, and members of the pair are delimited by a space.
 I'd like to end up with something like a range of 2-tuples, which I can
 then sort with a lambda. I'm running into problems trying to do this,
 after splitting on commas:

 Tuple!(int,int) coord = to!(int[])(splitter(pairString," ").array[]);

 ...which may not even be a good idea, I don't know. I've been following
 D for a long time, but this is the first time I've tried to actually use
 it; this seems like the kind of thing that should take just a few lines,
 if only I knew the libraries and range concepts well enough.

 To be clear, this is what I have:

 "192 14, 301 3, 578 0, 0 17"

 ...and this is what I want:

 [(578,0),(301,3),(192,14),(0,17)]

 What's the best way to do this? Should I be using map!() somewhere?

 Thanks,
 Adam
With no promises on performance and with a bonus mind-blowing format string... :) I am sure it can be improved a lot. import std.stdio; import std.algorithm; import std.range; import std.conv; void main() { auto input = "192 14, 301 3, 578 0, 0 17"; auto result = input .splitter(',') .map!splitter .joiner .map!(to!int) .chunks(2) .map!array .array .sort() .retro; writeln(result); writefln("[%((%(%s,%))%|,%)]", result); } Prints both an array of arrays and the same format that you wanted: [[578, 0], [301, 3], [192, 14], [0, 17]] [(578,0),(301,3),(192,14),(0,17)] Ali
Jun 01 2015
parent reply "Adam" <stiff example.com> writes:
     auto result = input
                   .splitter(',')
                   .map!splitter
                   .joiner
                   .map!(to!int)
                   .chunks(2)
                   .map!array
                   .array
                   .sort()
                   .retro;
Thanks for the reply. I'm a bit confused by the splitter followed immediately by the joiner...and then it kinda falls apart for me. Here's where I've ended up: auto result = input .splitter(",") // range of strings .map!(v => v.splitter(" ") // range of ranges strings .array // range of arrays of strings .to!(int[])) // range of arrays of ints .Tuple!(int,int); Everything is fine until I try to instantiate Tuples with my arrays. Then I get an error that says none of the overloads of the constructor are callable with these arguments. But I see which makes me think it should work. Am I doing something wrong?
Jun 01 2015
parent "Adam" <stiff example.com> writes:
 Everything is fine until I try to instantiate Tuples with my 
 arrays. Then I get an error that says none of the overloads of 
 the constructor are callable with these arguments. But I see 

 which makes me think it should work. Am I doing something wrong?
Alright! I got what I wanted. Posting here for any fellow noobs who may stumble across this and care what I was screwing up. It looks like I accidentally gave a bad example, because I needed to sort on the second elements ascending, not the first elements descending. The lambdas I was feeding to sort were not working because of the crazy types coming from the range methods, and it turns out that I did not need tuples, since I could get a proper sort from an array. This is what I ended up with (plus a couple of filters that I'm omitting for clarity): auto result = input .splitter(",") .map!(v => v.splitter(" ") .map!(a => a.to!(int)) .array() ) .array() .sort!("a[1]<b[1]"); Thanks Ali and Dennis for taking time to respond.
Jun 01 2015
prev sibling parent "Dennis Ritchie" <dennis.ritchie mail.ru> writes:
On Monday, 1 June 2015 at 22:31:38 UTC, Adam wrote:
 Hi,

 I have a string of pairs of integers, where pairs are delimited 
 from each other by commas, and members of the pair are 
 delimited by a space. I'd like to end up with something like a 
 range of 2-tuples
I can offer this option: import std.stdio, std.algorithm, std.array, std.range, std.format, std.typecons; void main() { string s = "192 14, 301 3, 578 0, 0 17"; int[] arr; int tmp; foreach (el; s.split) { formattedRead(el, "%s", &tmp); arr ~= tmp; } Tuple!(int, int)[] tup; foreach (el; zip(arr.stride(2), arr.dropOne.stride(2))) { tup ~= tuple(el[0], el[1]); } tup.sort!"a[0] > b[0]"; writeln(tup); } /*[Tuple!(int, int)(578, 0), Tuple!(int, int)(301, 3), Tuple!(int, int)(192, 14), Tuple!(int, int)(0, 17)]*/
Jun 01 2015