How to sort by duplicates only - sorting

I am designing a system were every song a user plays will get logged in my redis DB. I am then creating a Top Played section on the app. The app will index my DB and pull back the most played tracks (In other words, the tracks with the most duplicates!) If rihanna got played 4 times, taylor swift 1 time and U2 played lets say 2 times. I want rihanna to be on top of the list, u2 to be second and then taylor swift to be last.
My Question:
How can i sort with redis by duplicates? Or what can i do to achieve my goal?
What i tried:
I tried doing the redis-cli sort top_played alpha but of course, no luck as thats going by Alphabet.
Below is an example of the order i want.
1. Rihanna
2. U2
3. Taylor Swift
Below is my database output:
redis-cli lrange top_played 0 7
1) "u2"
2) "u2"
3) "taylor swift"
4) "rihanna"
5) "rihanna"
6) "rihanna"
7) "rihanna"

You need a SORTED SET, NOT a LIST, to save your data.
With SORTED SET, you can count how many times a track has been played. Each time when a track played, you can call ZINCRBY players 1 track-name to increase the counter of the specified track. In this way, Redis sorts all tracks with the played frequency. When you want to get top N track, just issue the following command: ZREVRANGE players 0 N-1.

Related

How many times do I have to repeat a specific shuffle of playing cards to get back to where I started?

This is my first post on Stack Overflow, so please excuse my mistakes if I'm doing something wrong.
Ok so I'm trying to find an algorithm/function/something that can calculate how many times I have to do the same type of shuffle of 52 playing cards to get back to where I started.
The specific shuffle I'm using goes like this:
-You will have two piles.
-You have the deck with the back facing up. (Lets call this pile 1)
-You will now alternate between putting a card in the back of pile 1 Example: Let's say you have 4 cards in a pile, back facing up, going from 4 closest to the ground and 1 closest to the sky (Their order is 4,3,2,1. You take card 1 and put it beneath card 4 mening card 1 is now closest to the ground and card 4 is second closest, order is now 1,4,3,2. and putting one in pile 2. -Pile 2 will "stack downwards" meaning you will always put the new card at the bottom of that pile. (Back always facing up)
-The first card will always get put at the back of pile 1.
-Repeat this process until all cards are in pile 2.
-Now take pile 2 and do the exact same thing you just did.
My question is: How many times do I have to repeat this process until I get back where I started?
Side notes:
- If this is a common way of shuffling cards and there already is a solution, please let me know.
- I'm still new to math and coding so if writing up an equation/algorithm/code for this is really easy then don't laugh at me pls ;<.
- Sorry if I'm asking this at the wrong place, I don't know how all this works.
- English isn't my main language and I'm not a native speaker either so please excuse any bad grammar and/or other grammatical errors.
I do however have a code that does all of this (Link here) but I'm unsure if it's the most effective way to do it, and it hasn't given a result yet so I don't even know if it works. If you wan't to give tips or suggestions on how to change it then please do, I would really appreciate it. It's done in scratch however because I can't write in any other languages... sorry...
Thanks in advance.
Any fixed shuffle is equivalent to a permutation; what you want to know is the order of that permutation. This can be computed by decomposing the permutation into cycles and then computing the least common multiple of the cycle lengths.
I'm not able to properly understand your algorithm, but here's an example of shuffling 8 elements and then finding the number of times that shuffle needs to be repeated to get back to an unshuffled state.
Suppose the sequence starts as 1,2,3,4,5,6,7,8 and after one shuffle, it's 3,1,4,5,2,8,7,6.
The number 1 goes to position 2, then 2 goes to position 5, then 5 goes to position 4, then 4 goes to position 3, then 3 goes to position 1. So the first cycle is (1 2 5 4 3).
The number 6 goes to position 8, then 8 goes to position 6. So the next cycle is (6 8).
The number 7 stays in position 7, so this is a trivial cycle (7).
The lengths of the cycles are 5, 2 and 1, so the least common multiple is 10. This shuffle takes 10 iterations to get back to the intitial state.
If you don't mind sitting down with pen and paper for a while, you should be able to follow this procedure for your own shuffling algorithm.

Most efficient way to repeatedly pair up a group of users for a quick game

I have an application where users sign on to play a quick 1v1 game (20 seconds duration). I would like to know the most efficient way to pair each user up with another user to play the game and move onto the next user without playing the same user multiple times in a row.
My first idea was to have two queue's containing the user id's of each online user. Whenever a new user goes online I would add them to whichever queue is the shortest and constantly be popping one person off the top of each queue to play each other. After the game I would simply add each user to the same queue to avoid them playing each other again. This seems good but I would like to see if there are any other more efficient ways to do this concept without needing to keep a list of previous users played on the server.
You need to matchmaking system that will prioritize players who have been waiting the longest.
You only need 1 queue and you also need to keep track of users history using a table. The table can either be temporary session data or a database table if you want permanent data across multiple sessions or if the match making server crashes. The table should have the playerID and an array of previous playerIDs that they previously played against. It can be best to limit the size of the array and use LIFO as you might not want to just store the players most recent match ups i.e. match history. Also the player could run out of players to play against if they already played against everyone else online. The table should look like this:
playerID (integer)
previousPlayerIDs (array of integers)
When a match starts you can update the the previousPlayerIDs for all the players in the match. You need to listen to an event when a player has joined the queue lets call it onPlayerJoin(). If the queue has more than 1 player you should take longest queuing player and compare their playerID against the previousPlayerIDs of each player until you find no history of a match up.
const historyLimit = 10;
function onPlayerJoin(Player newPlayer){
playerQueue.push(newPlayer);
if(playerQueue.length > 1){
for(let a=0; a<playerQueue.length-1; a++){
Player player = playerQueue[a];
for(int i=a+1; i<playerQueue.length; i++){
Player otherPlayer = playerQueue[i];
//if the player have not played before
if(otherPlayer.previousPlayerIDs.indexOf(player.id) > -1){
//save match up
player.previousPlayerIDs.push(otherPlayer.id);
otherPlayer.previousPlayerIDs.push(player.id);
//limit matchup histroy
if(player.previousPlayerIDs.length > historyLimit){
player.previousPlayerIDs.removeAt(0);
}
if(otherPlayer.previousPlayerIDs.length > historyLimit){
otherPlayer.previousPlayerIDs.removeAt(0);
}
//create lobby and remove players from the queue
createLobby(player, otherPlayer);
playerQueue.removeAt(a);
playerQueue.removeAt(i);
}
}
}
}
}
It is possible for a player to have played everyone else and they are waiting for someone to come online that they haven't played against before. You will need a reoccurring event to check if the longest waiting player has been waiting too long. If this is the case just ignore the matching of previousPlayerIDs and create a lobby for the the player up with another potentially long waiting player.
If you want you could add more columns to the table such as a timestamp when they joined the queue and their match making rank (elo). But if you just want to prioritize the most recent player you don't need these other columns.
Also this solution might not scale up very well if you have massive amounts of concurrent user but it should be fine if you have less than 1,000-10,000
Your idea doesn't work. Eventually (possibly very quickly), you'll end up in a position where two players who have played previously end up in separate queues. You can't guarantee that they'll never be selected to play together again.
Imagine this simple case:
Queue 1 Queue 2
A B
C
A and B play, and get added to Queue 2:
Queue 1 Queue 2
C A
B
A and C play, and get added to Queue 1:
Queue 1 Queue 2
A B
C
Now A and B play again. C never got the opportunity to play B.
This particular example is unlikely to occur, true. But something similar can happen even with larger queues as the space between player X and all the players he's played over time increases. The likelihood of ending up with two players playing each other again without having played every other potential player is quite high. I suspect the probability is similar to the birthday problem.
Your solution seems fine, but you should just use a single queue.

Operations on Two Streams of Data - Design Algorithm

I have seen this algorithm question or variants of it several times but have not found or been able to determine an optimal solution to the problem. The question is:
You are given two queues where each queue contains {timestamp, price}
pair. You have to print "price 1, price 2" pair for all those
timestamps where abs(ts1-ts2) <= 1 second where ts1 and price1 are
from the first queue and ts2 and price2 are from the second queue.
How would you design a system to handle these requirements?
Then a followup on this questions: what if one of the queues is slower than the other (data is delayed). How would you handle this?
You can do this in a similar fashion to the merging algorithm from merge sort, only doubled.
I'm going to describe an algorithm in which I choose queue #1 to be my "main queue." This will only provide a partial solution; I'll explain how to complete it afterwards.
At any time you keep one entry from each queue in memory. Whenever the two entries you have uphold your condition of being less than one second apart, print out their prices. Whether or not you did, you discard the one with the lower time stamp and get the next one. If at any point the time stamp from queue #1 is lower than that from queue #2, discard entries from queue #1 until that is no longer the case. If they both have the same time stamp, print it out and advance the one from queue #1. Repeat until done.
This will print out all the pairs of "price1, price2" whose corresponding ts1 and ts2 uphold that 0 <= ts1 - ts2 <= 1.
Now, for the other half, do the same only this time choose queue #2 as your "main queue" (i.e. do everything I just said with the numbers 1 and 2 reversed) - except don't print out pairs with equal time stamps, since you've already printed those in the first part.
This will print out all the pairs of "price1, price2" whose corresponding ts1 and ts2 uphold that 0 < ts2 - ts1 <= 1, which is like saying 0 > ts1 - ts2 >= -1.
Together you get the printout for all the cases in which -1 <= ts1 - ts2 <= 1, i.e. in which abs(ts1 - ts2) <= 1.
Additionally to the queues use two hashmaps (each exclusive for one queue)
As soon as a new item arrives strip the seconds out and use this as the key of the corresponding hashmap.
Using the very same key, retrieve all the items in the other hashmap.
One by one compare if the actual retrieved items are 1 second away of the item in bullet 2.
Note that this will fail to detect items with a difference in minutes: 10:00:59 and 10:01:00 will not be detected.
To solve this:
for items like XX:XX:59 you will need to hit the hashmap twice using keys XX:XX and XX:XX+1.
for items like XX:XX:00 you will need to hit the hashmap twice using keys XX:XX and XX:XX-1.
Note: do a date addition (not a mathematical one) since it will automatically deal with things like 01:59:59 + 1 = 02:00:00 or Monday 1 23:59:59 becoming Tuesday 2 00:00:00.
BTW, this algorithm also deals with the delay issue.
The speed of the queues does not matter at all if the algorithm is based on the comparison of timestamps alone. If one queue is empty and you cannot proceed just check periodically until you can continue.
You can solve this by managing a list for one of the queues. In the algorithm below the first was chosen, therefore it is called l1. It works like a sliding window.
Dequeue the 2nd queue: d2.
While the timestamp of the head of l1 is smaller than the one of d2 and the difference is greater than 1: remove the head from l1.
Go through the list and print all the pairs l1[i].price, d2.price as long as the difference of the timestamps is smalller than 1. If you don't reach the end of the list, continue with step 1.
Get the next element from the first queue and add it to the list. If the difference between the timestamps is smaller than 1 print the prices and repeat, if not continue with step 1.
here is my solution, you need following services.
Design a service to read the message from Queue1 and push the data to DB
Design another service to read the message from Queue2 and push the data to same DB.
Design another service to read the data from DB and print the result as per the frequency of result needed.
Edit
above specified system is designed ,keepin below point in mind
Scalablity - if load for system increases number of services can be scale up
Slowness as already mention one queu is slow then other , chances are ,first queue recieving more message then second ,hence not able to produce desired out put.
Otput Frequencey in future if requirement changes and instead of 1 sec difference we want to show 1 hour diffference ,then it is also very much possible.
Get the first element from both queues.
Compare the timestamps. If within one second, output the pair.
From the queue that gave the earlier timestamp, get the next element.
Repeat.
EDIT:
After #maraca's comment, I had to rethink my algorithm. And yes, if on both queues there are multiple events within a second, it will not produce all combinations.

Resorting items with a single database update

Let's say you're reordering items in your queue on Netflix. For every example I've seen of this sort of thing, when you move the last item to the top, it updates every record in the database, one at a time.
1. One Fine Day ==> change sort order from 1 to 2
2. Two and a Half Men ==> change sort order from 2 to 3
3. Three Kings (move to top) ==> change sort order from 3 to 1
Is there a better way to do this? Maybe one that only requires one database update each time you reorder in item? Consider this:
1. One Fine Day ==> do nothing (sort order stays at 1)
2. Two and a Half Men ==> do nothing (sort order stays at 2)
3. Three Kings (move to top) ==> change sort order from 3 to 0
Moving an item between two other items would split the difference between the sort orders:
1. One Fine Day ==> do nothing (sort order stays at 1)
2. Two and a Half Men ==> do nothing (sort order stays at 2)
3. Three Kings (move to mid) ==> change sort order from 3 to 2.5
To go one step further, we can use a larger character set than just digits, maybe going to base64 and sorting alphabetically, which would give you near unlimited resorting before having to reorder all the items to keep working space between items.
Anyways, what is the smartest way to hit your DB when resorting?
Your scenario, as I understood it, is the following:
For the sake of simplicity, let's imagine that we have 3 tables Movies, Users and UserPreferenes (the last one, with the columns UserId, MovieId and Ordinal).
Each time an user changes his preference over the sorting of his favorite movies, we should update the UserPreferences table.
But that usually requires updating the Ordinal column for at least 2 records (with some exceptions, but I'm not narrowing the overall logic to those cases)
So, the question would be: how can we avoid multiple updates and update only one record instead?
If the above is correct, a workaround solution would be denormalization. There is no general solution and with the risk of caveats on each direction you would choose, there are a couple of alternatives that I suggest you should consider:
To have not three, but only two columns in the UserPreferences, by keeping the UserId column and storing a sequence of the user's favorite movies ids in another column, OrderedMovieIds.
To convert the Ordinal column into a finite number of columns which would indicate the preferences of the user: Ordinal1, Ordinal2, ... OrdinalN (of course this is limited by the table maximum number of columns).

sorting cards with wildcards

i am programming a card game and i need to sort a stack of cards by their rank. so that they form a gapless sequence.
in this special game the card with value 2 could be used as a wild card, so for example the cards
2 3 5
should be sorted like this
3 2 5
because the 2 replaces the 4, otherwise it would not be a valid sequence.
however the cards
2 3 4
should stay like they are.
restriction: there an be only one '2' used as a wildcard.
2 2 3 4
would also stay like it is, because the first 2 would replace the ACE (or 1, whatever you call it).
the following would not be a valid input sequence, since one of the 2s must be use as a wildcard and one not. it is not possible to make up a gapless sequence then.
2 4 2 6
now i have a difficulty to figure out if a 2 is used as a wildcard or not. once i got that, i think i can do the rest of the sorting
thanks for any algorithmic help on this problem!
EDIT in response to your clarification to your new requirement:
You're implying that you'll never get data for which a gapless sequence cannot be formed. (If only I could have such guarantees in the real world.) So:
Do you have a 2?
No: your sequence must already be gapless.
Yes: You need to figure out where to put it.
Sort your input. Do you see a gap? Since you can only use one 2 as a wildcard, there can be at most one gap.
No: treat the 2 as a legitimate number two.
Yes: move the 2 to the gap to fill it in.
EDIT in response to your new requirement:
In this case, just look for the highest single gap, and plug it with a 2 if you have a 2 available.
Original answer:
Since your sequence must be gapless, you could count the number of 2s you have and the sizes of all the gaps that are present. Then just fill in the highest gap for which you have a sufficient number of 2s.

Resources