Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature - Preferred spread #161

Closed

Conversation

frysch
Copy link
Contributor

@frysch frysch commented Nov 27, 2019

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.

Copy link
Owner

@brendon brendon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?


modifier = min < max ? 1 : -1

if (max - min).abs < ranker.preferred_spread * 2
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you be able to explain this one out for me? Especially the significance of * 2 and 0.3 :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a very good question 😀. I can't remember exactly the reason for that *2. But from reading it now i'd say it's checking that there's enough space both before and after. And if it's not: the magic number 0.3 enters the stage and draws a rabbit out from the hat. That might have to be removed. It's just another way of minimizing recalculations, since we're using it in a place where users tend to drag'n drop items on top, which causing the space to run out eventually. This just delays that event to happen really.

Makes any sense?

@frysch
Copy link
Contributor Author

frysch commented Feb 20, 2020

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
Copy link
Owner

brendon commented Feb 20, 2020

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
Copy link
Contributor

aried3r commented Oct 1, 2020

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
Copy link
Contributor Author

frysch commented Oct 1, 2020

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
Copy link
Owner

brendon commented Oct 4, 2020

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
Copy link

cpb commented Feb 3, 2023

As shown in the activity, I've created an updated branch for this. #195

@brendon what do you mean by "folded"?

@brendon
Copy link
Owner

brendon commented Feb 6, 2023

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
Copy link
Owner

brendon commented Jun 4, 2024

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.

@brendon brendon closed this Jun 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants