Thread overview
Splitting a range into a range of tuples
Jun 01, 2015
Adam
Jun 01, 2015
Ali Çehreli
Jun 02, 2015
Adam
Jun 02, 2015
Adam
Jun 01, 2015
Dennis Ritchie
June 01, 2015
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
June 01, 2015
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

June 01, 2015
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)]*/
June 02, 2015
>     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 this: http://dlang.org/phobos/std_typecons.html#.Tuple.this.2 , which makes me think it should work. Am I doing something wrong?
June 02, 2015
> 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 this: http://dlang.org/phobos/std_typecons.html#.Tuple.this.2 , 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.