Reputation: 11657
I found this one liner which joins same lines from multiple files. How to add a space between two lines?
If line 1 from file A is blue and line 1 from file B is sky, a get bluesky, but need blue sky.
say $_ for [Z~] @*ARGS.map: *.IO.lines;
Upvotes: 7
Views: 193
Reputation: 9600
Note: definitely don't do this in anything approaching real code. Use (one of) the readable ways in Liz's answer.
If you really want to use the same structure as [Z~]
– that is, an operator modified by the Zip meta-operator, all inside the Reduce meta-operator – you can. But it's not pretty:
say $_ for [Z[&(*~"\x20"~*)]] @*ARGS.map: *.IO.lines
Here's how that works: Z
can take an operator, so we need to give it an operator that concatenates two strings with a space in between. But there's no operator like that built in. No problem – we can turn any function into an infix operator by surrounding it with [ ]
(the infix form).
So all we need is a function that joins two strings with a space between them. That also doesn't exist, but we can create one: * ~ ' ' ~ *
. So, we should be able to shove that into our infix form and pass the whole thing to the Zip operator Z[* ~ ' ' ~ *]
.
Except that doesn't work. Because Zip isn't really expecting an infix form, we need to give it a hint that we're passing in a function … that is, we need to put our function into a callable context with &( )
, which gets us to Z[&(* ~ ' ' ~ *)]
.
That Zip expression does what we want when used in infix position – but it still doesn't work once we put it back into the Reduce/[ ]
operator that we want to use. This time, the problem is due to something that may or may not be a bug – even after discussing it with jnthn on github, I'm still not sure whether this behavior is intended/correct.
Specifically, the issue is that the Reduction meta-operator doesn't allow whitespace – even in strings. Thus, we need to replace * ~ ' ' ~ *
with *~"\c[space]"~*
or *~"\x20"~*
(where \x20
is the hex value of
in Unicode/ASCII). Since we've come this far into obfuscated code, I figure we might as well go all the way. And that gets us back to
say $_ for [Z[&(*~"\x20"~*)]] @*ARGS.map: *.IO.lines
Again, I'm not recommending that you do this. (And, if you do, you could at least make it slightly more readable by saving the * ~ ' ' ~ *
function as a named variable in the previous line, which at least gets you whitespace. But, really, just use one of Liz's suggestions).
I just thought this gives a useful window into some of the darker and more interesting corners of Raku's strangely consistent behavior.
Upvotes: 5
Reputation: 26979
This is using the side-effect of .Str
on a List
to add spaces between the elements:
say .Str for [Z] @*ARGS.map: *.IO.lines
The Z
will create 2 element List
objects, which the .Str
will then stringify.
Or even shorter:
.put for [Z] @*ARGS.map: *.IO.lines
where the .put
will call the .Str
for you and output that.
If you want anything else inbetween, then you could probably use .join
:
say .join(",") for [Z] @*ARGS.map: *.IO.lines
would put comma's between the words.
Upvotes: 11