brendon / ranked-model

An acts_as_sortable/acts_as_list replacement built for Rails 4+
https://github.com/mixonic/ranked-model
MIT License
1.09k stars 134 forks source link

Feature - Preferred spread #161

Closed frysch closed 5 months ago

frysch commented 5 years ago

Adding an option for preferred gap size between ranked models which is being used when adding items first and last. It's also used when rebalancing_ranks is triggered.

Doing it because we're using the gem together with Ember and some drag n drop. Users tend to drag a lot of items to the top (:first). We want to avoid collisions as much as possible, cause when we're touching other models than the one being updated, the data is no longer synced between front and backend.

Do whatever you want with this PR, just throwing it out there.

frysch commented 4 years ago

Firstly I must apologise for how long it's taken me to look at this. It looks like a great idea. I've always not liked the way the list will choke after surprisingly few inserted records at :first or :last due to the halving of the gap each time. There must be a better way.

Ideally it'd be good to know roughly how many items a list would contain, then create large gaps appropriately. I'm wondering if your solution should be made the default with some kind of default gap value that suits most people?

The hard part is probably to figure out that default gap. But pretty much any value will create a lot more space in the beginning and end of the list than the current solution which run out of space after 30-ish :first placements.

brendon commented 4 years ago

Haha! I feel like a computer scientist must have already solved this problem :D

I definitely think the practice of dividing the space equally each time is basically a non-starter for most use cases (even the default where things keep getting added to the bottom of the list by default - we still run out of space after the 30 or so placements).

I have seen an alternative where a string column is used (though I guess one could also use a floating point column). Items are added sequentially initially (1-1,2-2,3-3,4-4...)(id-position). But then if an item is moved up in front of another (say 4 goes before 3) then you'd end up with (1-1,2-2,4-2.9,3-3) (or some variation using strings instead with the letters of the alphabet).

Of course there's still limits but between every item is the same amount of 'space'.

I can already see issues with that in my head, but just thinking aloud :D

aried3r commented 4 years ago

Hey! At work we might also be interested in this and were wondering how we could progress this. If I understood correctly, the question remains what a good algorithm for calculating the initial spread is? Or is there something else (for example the 0.3 and * 2 discussion)?

We have a rough idea how our data will look like so defining a hardcoded spread would work for us.

frysch commented 4 years ago

Hey! At work we might also be interested in this and were wondering how we could progress this. If I understood correctly, the question remains what a good algorithm for calculating the initial spread is? Or is there something else (for example the 0.3 and * 2 discussion)?

We have a rough idea how our data will look like so defining a hardcoded spread would work for us.

Dunno, i have sort of checked out from this :). We are using this fork in production and it works well in our case. I guess we're missing out on some goodies that has been added since in master thou.

brendon commented 4 years ago

I'm still totally keen to solve this problem. Equal spacing really doesn't work when things are always appended to the end of the list. It's an exponential problem by the looks. The list can only be folded so many times before running out of accuracy. I still like the idea of using some kind of sub-spacing per my message above, but I get a gut feeling this might also suffer from the same problem eventually but it certainly won't cause problems with appending where list items don't often get shuffled.

cpb commented 1 year ago

As shown in the activity, I've created an updated branch for this. https://github.com/brendon/ranked-model/pull/195

@brendon what do you mean by "folded"?

brendon commented 1 year ago

Thanks @cpb, I've grown in my understanding of this problem since 2020 and a preferred_spread is probably the best way to go. All the other options (e.g. string columns, larger integers) just either obscure the problem (text is still a number eventually) or delay the problem.

By folding I mean halving the remaining space between the top-most or bottom-most position integer and the min or max each time. It's like trying to fold a piece of paper. It gets exponentially harder each time :) I'll take a look at the PR. I didn't like the arbitrary math without much explanation (per above) but perhaps you've fixed that?

brendon commented 5 months ago

I'm going to close this for now. I think it's a worthy thing to pursue for this gem. I wonder if we have a config called expected_list_size with a default of something like 500. We then use this estimate to generate appropriate gaps between items. The larger the list, the larger the gaps between?

In my new gem https://github.com/brendon/positioning I opted for sequential integers. This removes the problem but adds cost on each insertion as we need to potentially move things out of the way. I'd say the vast majority of lists append items to the end of the list by default which doesn't require any work with sequential integers but does cause problems in ranked-model.