4 ms·
Hang on. Off by one issues are the argument frequently given in favour of zero-based indices, not the other way around. For example, let's iterate through items
by Benjamin_Dobell 2y ago
Hang on. Off by one issues are the argument frequently given in favour of zero-based indices, not the other way around. For example, let's iterate through items placing them in 3 different groups;
JS:
for (let i = 0; i < items.length; i++) {
groups[i % 3].push(items[i]);
}
Lua:
for i = 1, #items do
table.insert(groups[((i - 1) % 3) + 1], items[i])
end
Don't get me wrong. I like Lua, I've made my own IDE for it, https://plugins.jetbrains.com/plugin/14698-luanalysis https://plugins.jetbrains.com/plugin/14698-luanalysis, but this is definitely not an argument in favour of 1-based indices.
- Jerrrry 2y agoYour second example subtracts and adds 1 nearly arbitrarily, which wouldn't be needed if the convention of the 0-index wasn't so widespread.
- School-Cotton 2y agoYou need the first three elements to go into the first group, the next three to go into the second group, and so on. How would you write it?
- binary132 2y agoThat’s not what that loop does, it puts one item into each next group and loops back over the groups after every three items. Really it ought to be a by-three stepped loop over items, inserting each into each group inline: groups[1], groups[2], groups[3] = items[i], items[i+1], items[i+2] If the group count is dynamic, you can just loop over groups instead, and then step through items by #groups, inserting.
- School-Cotton 2y agoFair enough, for some reason I thought it was i/3 and not i%3. Still, I think the point stands.
- Benjamin_Dobell 2y agoIf it is dynamic one of the loops will also suffer from an off-by-one issue. You can't add 1-based indices together like you can zero-based indices. It's also worth noting your solution exhibits similar off-by-one behaviour. The left hand side constants (integer values) do not match the right. It's error prone.
- binary132 2y agosorry, where is the off by one? the code offered is of course only a solution for the fixed-size groups
- Jerrrry 2y ago>You can't add 1-based indices together like you can zero-based indices. I think you are right but I am unable to articulate why. But I think 0 based indexes are able to fruitfully capture "going nowhere" iteratively than 1 based indexes, which do require a decrement in that circumstance.
- binary132 2y agowhy not just iterate in steps of three over items for each next group? seems a bit contrived.
- Benjamin_Dobell 2y agoBecause it's a simplified example to demonstrate the problem. If you do as you've described you need three separate assignments. What happens when the number of groups is dynamic? Nested loop? This is suddenly getting a lot more complicated.
- binary132 2y agoYes, that’s what I was saying: for each group: for i in steps of #groups: assign item to this group I think that’s a lot easier to comprehend than the modulus trick
- dvdkon 2y agoFor a lot of people the modulo approach isn't a "trick", it's just the intuitive way to split items into residue classes. And it's likely a little more cache-efficient.
- binary132 2y agowell clearly your comment is meant to demonstrate that it’s a clumsy approach in a 1-indexed syntax, so perhaps a different technique would be more facile here… such as a counting method :)
- geocar 2y agoOff by one issues are also an argument given in favour of no indexing. groups=new Array(3).fill([]) items.reduce(function(a,x,y){y=a.shift();y.push(x);a.push(y);return a},groups) Array languages typically have a reshaping operator so that you can just do something like: groups:3 0N#items Does that seem so strange? 0N is just null. numpy has ...reshape([3,-1]) which wouldn't be so bad in a hypothetical numjs or numlu; I think null is better, so surely this would be nice: groups = table.reshape(items,{3,nil}) -- numlu? groups = items.reshape([3,null]) // numjs? Such a function could hide an ugly iteration if it were performant to do so. No reason for the programmer to see it every day. Working at rank is better. On the other hand, Erlang is also 1-based, and there's no numerl I know of, so I might write: f(N,Items) -> f_(erlang:make_tuple(N,[]),Items,0,N). f_(Groups,[],_,_N) -> Groups; f_(G,Items,0,N) -> f_(G,Items,N,N); f_(G,[X|XS],I,N) -> f_(setelement(I,G,X),XS,I-1,N). I don't think that's too bad either, and it seems straightforward to translate to lua. Working backwards maybe makes the 1-based indexing a little more natural. n = 0 for i = 1,#items do if n < 1 then n = #groups end table.insert(groups[n],items[i]) n = n - 1 end Does that seem right? I don't program in lua very much these days, but the ugly thing to me is the for-loop and how much typing it is (a complaint I also have about Erlang), not the one-based nature of the index I have in exactly one place in the program. The cool thing about one-based indexes is that 0 meaningfully represents the position before the first element or not-an-element. If you use zero-based indexes, you're forced to either use -1 which precludes its use for referring to the end of the list, or null which isn't great for complicated reasons. There are other mathematical reasons for preferring 1-based indexes, but I don't think they're as cool as that.
- MomsAVoxell 2y agoYes, that is what is so frustrating about this argument every single time it comes up, because both sides in the debate can be equally false, or equally true, and its really only a convention and awareness issue, not a language fault. It’s such a binary, polarizing issue too, because .. here we are again as always, discussing reasons to love/hate Lua for its [0-,non-0] based capabilities/braindeadednesses.. In any case, I for one will be kicking some Luon tires soon, as this looks to be a delightful way to write code .. and if I can get something like TurboLua going on in TurboLuon, I’ll also be quite chuffed ..