From: Gavin Sinclair Date: 2004-05-09T15:01:54+09:00 Subject: Re: How to get the last 5 elements of an array? On Sunday, May 9, 2004, 9:04:07 AM, Jeff wrote: > --- Gavin Sinclair wrote: >> On Sunday, May 9, 2004, 7:23:12 AM, Jeff wrote: >> >> (where x == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) >> >> >> Yes the anomaly is that ruby only modularizes indices i for >> >> -length <= i < length. A purist might say modular arithmetic >> >> should be applied globally or not at all, but this would give >> >> >> >> x[10..15] == x[20..25] == x[-20..-15] == [1,2,3,4,5,6] >> >> I'd happily accept x[10..15] == x[20..25] == x[-20..-15] == [] >> >> >> which could fail to indicate Something's Wrong. I see ruby's >> >> subset of modular arithmetic as a middle ground between convenience >> >> and saftey. One can always write ModArray trivially, after all. >> >> > Whoa hang on, I didn't read the OP well enough. At least x[-3..2] >> > should return [8, 9, 10, 1, 2, 3], otherwise this isn't even a >> > subset of modular arithmetic, it's something else. >> >> Yes, it's Weird. >> > I am suddenly inclined to take a purist view of arrays: either modular > arithmetic or no modular arithmetic. As such, there is only one rule > to know: all the boundary cases are consistent and predictable. I'm not convinced by this. I like consistency as much as you do, but there are different ways to achieve consistency. The main thing to consider, perhaps, is complexity. You're shooting for an ultra-simple approach, which is admirable, but I don't think either no-modular or all-modular are that useful. And if you want (m..n).map { |i| arr[i] /* or arr[i % arr.size] */ } you know where to find it :) At the end of the day, I've never needed wraparound functionality (arr[-4..6]), and I doubt I ever will. In fact, I doubt anyone will. >> Take this, though. Let y = [7, 8]. Now what could y[-1..1] mean? >> >> (-1..1) =~ [-1, 0, 1]. All elements of that range represent fair-game >> indices into y. So: >> >> y[-1..1] == [8, 7, 8] ??? >> > Since we have the ability to specify sets of integers inside [], I > think we are forced to view y as a function. y[-1..1] == [8, 7, 8] is > absolutely expected, to me. I put in 3 elements, I expect to get out > 3 elements. This is consistent for all cases: put in n, get out n. > We can make a truism of it, > y[a, b] == y[a..b] == [y[a], .. , y[b]] That's the mapping I coded above. A nitpick: y[a, b] is not intended to be the same as y[a..b]. arr[n,5] means grab the 5 elements starting at index 'n'. > With the current ruby behavior, can you list all the conditions under > which the above holds, and all the conditions and their outcomes when > the above doesn't hold? Will you remember 8 months from now, or will > you need to fire up irb to test it out again? Needing to fire up irb is one good test of how intuitive something is, and there are a few Ruby features that cause me to use irb every time I need them. However, I must accept that as part of life (and different things are intuitive to different people), and you can turn the negative into a positive: "Hey, I can just use irb to see what it does". > As you can see, my bias is towards consistency. It's simply amazing > how much code is devoted to special cases. That code is ugly and > distracting. I'm not particularly purist, but I sure am when it comes > to consistent behavior. I am borderline trolling now so I'll stop :) At the end of the day, I'd like a fairly complicated, but intuitive, implementation for Array#[m..n]. It ain't gonna happen, though. The current implementation is (I'm pretty sure) justified by some logic, and the implementation I'd like to see treats Array more like an ordered set than an array. a = [1, 3, 5, 7] a[-1..1] # -> [7, 1, 3] a[-10..10] # -> [1, 3, 5, 7] a[-5..-1] # -> [1, 3, 5, 7] # The question that # started this thread. b = [1, 2] b[-1..1] # -> [2, 1] # Not [2, 1, 2] Anyway, like I said, I don't see a great need for this stuff, although I would like [-5..-1] to "work" in all cases. Cheers, Gavin