sub interleave { @_[map $_&1 ? $_>>1 : ($_>>1)+($#_>>1), 1..@_] }
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: perfect shuffle
by Zaxo (Archbishop) on Nov 23, 2003 at 08:47 UTC | |
It took me a while to work out what you were getting at here. I'd call this interleave, not shuffle. The two arrays as arguments are a blind: they may or may not have the same number of elements. If warnings are active, they should add to an even number of elements. This is terribly obfuscated, if it works at all. What exactly do you mean it to do? Update: The Storm King reminds me that 'perfect shuffle' is the term for a uniform distribution of order. Not what your function produces. After Compline, | [reply] |
by sauoq (Abbot) on Nov 23, 2003 at 19:30 UTC | |
I believe a magician or card cheat would call it a perfect shuffle. I agree, however, that it should be given a different name in this context. I'd also prefer if the code was clearer. -sauoq "My two cents aren't worth a dime."; | [reply] |
|
Re: perfect shuffle
by bart (Canon) on Nov 23, 2003 at 08:58 UTC | |
or
p.s. A common name for this kind of functionality is "zip". See Language::Functional for an implementation. SO I changed the name for the function to reflect this. | [reply] [d/l] [select] |
|
Re: perfect shuffle
by duff (Parson) on Nov 23, 2003 at 17:54 UTC | |
You might want to change the description to be slightly more accurate. I mean, what it really does is take one list, halves it, then interleaves the halfs. Sure you can give it two arrays or lists as arguments, but it's not going to do the right thing if the they are different sizes (at least not what I would expect given the description). | [reply] |
|
Re: interleave (single shuffle)
by Roger (Parson) on Nov 24, 2003 at 01:22 UTC | |
But no error checking though, it assumes that both arrays are of the same size, as many monks have pointed out already. (I know that you only did it for fun and in real life would not do without error checkings.) Personally I would favour a more conservative approach like the following -
| [reply] [d/l] |
by ysth (Canon) on Nov 24, 2003 at 02:56 UTC | |
Given actual arrays, I would be more likely to say:
| [reply] [d/l] |
|
Re: interleave (single shuffle)
by Aristotle (Chancellor) on Nov 26, 2003 at 11:32 UTC | |
Now there are several things that irk me. One is the duplication of $_ / 2. The other is 1 .. @_ which surprised me for 1/10th of a second. Now IMHO it's much easier to see what's going on. But I'd write it differently:
That gets us rid of the constant evaluation of a condition and reduces the number of iterations by half. You might want to move the @_ / 2 invariant out of the loop as a final optimization. The inner loop is now extremly simple: two additions. This is faster than your cryptic bit ops version and still clear as day to read. Don't microoptimize, pick a good algorithm first. You'll always get more readable as well as faster code. Makeshifts last the longest. | [reply] [d/l] [select] |
by ysth (Canon) on Nov 27, 2003 at 02:03 UTC | |
Nice, but why the bit ops? This isn't assembler. sub interleave { @_[ map $_ % 2 ? $_ / 2 : ( $_ / 2 ) + ( $#_ / 2 ), 1 .. @_ ] }Perl is not assembler, only assembler code uses bit ops, ergo perl code never uses bit ops? There are as many valid subsets of Perl as there are Perl programmers, and then some. Every programmer should use the parts with which he/she is familiar, with due allowance for whatever audience, coworkers, etc. exist. Here at perlmonks, I'm only likely to veer from my "native dialect" when answering a newbie's question. To more directly address your question, this is an integer transformation problem and bit ops are part of my mental toolbox for that kind of problem. It didn't even occur to me to use /2 instead. Note that my code produces indices 0,5,1,6,2,7,3,8,4,9 for a list of 10, while your first version produces 0.5,5.5,1.5,6.5,2.5,7.5,3.5,8.5,4.5,9.5. They are equivalent, since array subscripts are converted to int, and your version is just as good as mine, but I was thinking only of integer operations and your thinking was more unbounded.
Now there are several things that irk me. One is the duplication of $_ / 2. The other is 1 .. @_ which surprised me for 1/10th of a second. sub interleave { @_[ map $_ / 2 + ( $_ % 2 ? $#_ / 2 : 0 ), 0 .. $#_ ] }I agree that 0 .. $#_ may be a little clearer. (Side thought: how about @_[ sort { ... } 0..$#_ ].) But you've introduced an error when there are an odd number of parameters. Try @_/2 instead. Also see Bart's version where he has a&&b instead of a?b:0. IMHO it's much easier to see what's going on. But I'd write it differently: sub interleave { @_[ map +( $_, $_ + @_ / 2 ), 0 .. $#_ / 2 ] } That gets us rid of the constant evaluation of a condition and reduces the number of iterations by half. You might want to move the @_ / 2 invariant out of the loop as a final optimization. The inner loop is now extremly simple: two additions. This is faster than your cryptic bit ops version and still clear as day to read. Don't microoptimize, pick a good algorithm first. You'll always get more readable as well as faster code.Thanks, that is a fair amount faster. But again, I wasn't actually trying to optimize, and your last example only works for an even number of parameters. | [reply] [d/l] [select] |
by Aristotle (Chancellor) on Nov 27, 2003 at 04:05 UTC | |
Yes, bit ops are available in Perl, but I don't find them a natural way to express this particular problem. It'd've taken a lot more effort to figure out your code if I hadn't used them extensively in assembler, back in the day. Just about every use of bit ops I've ever seen obscures rather than clarifies what's going on. In nearly all cases the motivation is microoptimization. That's what I got the impression was what you were trying to do, from the looks of your code. As for the other points: apologies, I did more than just replace the bit ops by equivalents and didn't test sufficiently. I even wrote a note that the code probably contains off-by-one errors, but then tested it a bit and it seemed to be ok. The two issues are orthogonal though, it's the other changes in the structure I made that introduced the problems, not the bit op replacement. As for performance in general, I think it would be worthwhile to do this in XS and stick it into List::Util. Makeshifts last the longest. | [reply] |