Ordering photos both by timestamp and manually - algorithm

Context
I'm working on a small web app to store photos. Photos are ordered according to their timestamp (the date they've been taken), and it's working great. Here's a simplified look at the database:
+--------------+-------------------+
| id | timestamp |
+--------------+-------------------+
| 1 | 1000000003 |
| 2 | 1000000000 |
+--------------+-------------------+
Now I'd like to add the possibility to re-order photos. And I can't find a way of doing that without any downsides.
What I did
I first added a column to the table to save a custom order.
+--------------+-------------------+-------------+
| id | timestamp | order |
+--------------+-------------------+-------------+
| 1 | 1000000003 | 1 |
| 2 | 1000000000 | 2 |
+--------------+-------------------+-------------+
First issue: I believe I can't order photos according to two different criteria, because it'd be hard to know which one has to be given precedence.
So I'm ordering them using the order column, and only this one. When I added the order column, I gave each photo a value so that the current order would remain. I now have photos ordered by order, in the same order as when they were ordered by timestamp.
I can now re-order some photos manually, and the other ones will stay where they belong. The first issue has been solved.
But now, I want to add a new photo.
Second issue: I know when the new photo I'm adding has been taken, but my photos aren't ordered by their timestamp anymore. This photo needs to be correctly ordered, thus it needs a correct order value.
This is the issue: a correct order value.
Here are two ways I could handle a new photo:
Give it an order value greater than others. In the previous table, a new photo would be given order = 3. This is obviously a bad idea, since it doesn't take its timestamp into account. A recent photo would still be the last one displayed.
"Insert" it where it belongs, according to its timestamp. Looking at the same table, if the timestamp of the new photo was 1000000002, the new photo would be given order = 2, and the order of every following photo would be increased by 1.
The second solution looks great, except in one case: if the order of the photo #2 had been manually changed to let's say 50, the new photo would have been given order = 50 even though it belongs among the first photos (according to its timestamp).
What I need
What I need is a way of ordering photos according to their timestamp and to their manually-set order.
Maybe you have a solution to the second issue I highlighted, or maybe you're aware of a whole other way to deal with this. Either way, thank you for your help.

At no point in your question do you mention computers or programming languages. This is OK (actually, it's a good approach, get the problem and solution worked out on paper before coding) and here's an answer which also ignores computers and programming languages.
Put all your photos into a shoebox in the order in which you get them.
Now, take three pieces of paper:
On page 1 write the numbers (one to a line) from 1 to N (the number of photos the box can hold). Whenever you put a photo in the box, write its timestamp on the line corresponding to its order in the box.
On page 2 write the timestamp of photo 1 a few lines down. Write a 1 on the same line. For the next photo, write its timestamp in the appropriate place on the paper, leaving as much space above and below as seems necessary for future photo insertions. Write a 2 on the same line. Continue until you run out of space between lines, when you need to copy all the information onto a new version of the page with more space for insertions. The information on this page is the same as the information on page 1, but with the two numbers on each line swapping positions.
On page 3 write the numbers from 1 to N again. As you collect each photo write its number from page 1 (ie its number in the sequence of all photo numbers) in the correct position for your manually-set ordering. You'll probably have to do a lot of rubbing-out and re-writing on this page as you decide that latecomers ought to be inserted high onto this page.
Now you have:
a store for your photos, the shoebox; you should already have realised that you can't store the photos in more than one order at a time;
three indexes (indices if you prefer); the first is fixed and simply assigns a unique sequence number to each photo; it also tells you the timestamp of each photo in the box;
the second index enables you to find the unique sequence number of a photo given its timestamp, and then find the photo in the shoebox;
the third index allows you to order photos as you wish; the first number on each line is the sequence number in the sorted order, the second number is the photo's unique sequence number from the first index.
All of this is an extremely long-winded way of telling you that, since you can't (either in a shoebox or a computerised data store) keep photos in multiple orders simultaneously, you will have to maintain indices for the orderings you wish to use. Those indices point (that's what an index does) from a number to a location in the shoebox, either directly or indirectly.

Related

Find Nth Occurrence of Largest Value in a row

I have some basic data on a rugby game, to be used in a scouting report. I need to:
Show which players have the highest PITA count (sum of all their other actions)
And
Show those players' 3 highest count actions - column headers are the different actions.
Pic of Dataset
The first half of my task was accomplished by the following index formula:
=if(C25=C24,index(C3:C17,small(if(large(B3:B17,2)=B3:B17,row(B3:B17)-2),2)), vlookup(large(B3:B17,2),B3:C17,2,false))
I've gotten the 3 players ranked by highest PITA count, which also includes tied values, as seen in the pink/salmon colored box. I was able to take the "Nth" value, so Player #2 and Player #8 are both shown correctly in 2nd and 3rd place, even though they have the same PITA value. Rather than Player #2 be shown twice since the Large function is looking for the same value.
I'd like to achieve similar to above, but display which type of action (column headers) is the player's 1st, 2nd, and 3rd most completed actions (blue columns). I am having trouble replicating the above formula to work horizontally and choose the correct column. Similar to above, I need it to be able to take the Nth value. The yellow highlighted row is an example of my problem, as I'd like it to show Ruck Disruption and then Tackler in the 1st Highest Action and 2nd Highest Action column, rather than it showing Ruck Disruption twice.
This is where I've gotten with said formula:
=if(large($E4:$L4,1)=0,"",index($E$2:$L$2,,match(large($E4:$L4,2),$E4:$L4,0)))
Link to spreadsheet: https://docs.google.com/spreadsheets/d/1P2msjxofWR8wfwjbfPYQexEzLEMSwVCwX5wNJUACZHI/edit?usp=sharing
Thanks in advance for any help.
Tried:
=if(large($E4:$L4,1)=0,"",index($E$2:$L$2,,match(large($E4:$L4,2),$E4:$L4,0)))
but keeps returning the first instance of "1" and therefore giving me Ruck Disruption instead of Tackler.
The way the get the player place seems may not have considered situation such as when there are two 1st place and two 2nd place, or even three 1st place, etc.
the formula below will take in all combinations and return PITA rank, PITA Count, and PlayerNumber as an arrary, it gives dinamic result, so that when player score the same PITA, they will be named as the same place, and can exceed 3 place if more than 3 same score appears:
=
LAMBDA(PLAYER,PITA,
LAMBDA(UPITA,
LAMBDA(UPITACOUNT,
LAMBDA(UPITACOUNT,
LAMBDA(RESULT_1,RESULT_2,RESULT_3,
LAMBDA(FIRST,SECOND,THIRD,
QUERY({
FIRST;
IF(COUNTA(INDEX(FIRST,,1))<3,SECOND,{"","",""});
IF(COUNTA(INDEX(FIRST,,1))+COUNTA(INDEX(SECOND,,1))<3,THIRD,{"","",""})
},"WHERE Col1 IS NOT NULL LABEL Col1'PITA rank',Col2'PITA Count',Col3'PlayerNumber'",0)
)(
MAKEARRAY(COUNTA(INDEX(RESULT_1,,1)),3,LAMBDA(ROW,COL,IFS(COL=1,"1st",TRUE,INDEX(RESULT_1,ROW,COL-1)))),
MAKEARRAY(COUNTA(INDEX(RESULT_2,,1)),3,LAMBDA(ROW,COL,IFS(COL=1,"2nd",TRUE,INDEX(RESULT_2,ROW,COL-1)))),
MAKEARRAY(COUNTA(INDEX(RESULT_3,,1)),3,LAMBDA(ROW,COL,IFS(COL=1,"3rd",TRUE,INDEX(RESULT_3,ROW,COL-1))))
)
)(
FILTER({PITA,PLAYER},PITA=INDEX(UPITACOUNT,1,1)),
FILTER({PITA,PLAYER},PITA=INDEX(UPITACOUNT,2,1)),
FILTER({PITA,PLAYER},PITA=INDEX(UPITACOUNT,3,1))
)
)(SORT({UPITA,COUNTIF(PITA,INDEX(UPITA,,SEQUENCE(UPITACOUNT)))},1,0))
)(COUNTA(UPITA))
)(UNIQUE(PITA))
)($C$3:$C$17,$D$3:$D$17)
one 1st and three 2nd:
two 1st and one 2nd:
five top:
more than one 3rd:
And this formula will return 3 results of the highest score actions of each player:
=ArrayFormula(
LAMBDA(DATA,
LAMBDA(TITLES,VALUES,
LAMBDA(RESULTS,
RESULTS
)(
BYROW(VALUES,LAMBDA(SCORE,
TRANSPOSE(IFNA(QUERY(SORT(TRANSPOSE({TITLES;SCORE}),2,0),"SELECT Col1 WHERE Col2>0 LIMIT 3",0),""))
))
)
)(INDEX(DATA,1),MAKEARRAY(COUNTA(INDEX(DATA,,1))-1,COUNTA(INDEX(DATA,1)),LAMBDA(ROW,COL,INDEX(DATA,ROW+1,COL))))
)($E$2:$L$17)
)

How to Create a List of Available Times after removing Downtimes from a Period

I have a grid which lists the Period (Start - End), and a list of Downtimes.
The downtimes are then sorted (to ensure chronological order based on the start time of the outage), using the following formula:
=SORT(INDIRECT("B4:C"&SUMPRODUCT(MAX((B4:B12<>"")*ROW(B4:B12)))),1)
After which I am trying to calculate the list of Available times (Uptimes).
Currently i have a mess of inflexible formulas as follows:
B26 =IF(B14<B15,B14,C15)
C26 =IF(C14<C15,C14,B16)
B27 =C16
C27 =B17
I am searching for either a universal single celled arrayformula, or a formula that can be dragged (down/across), that can calculate the list of Available times (Uptimes).
I am seeking formula solutions that will work in both Excel (Mac 2021) and Google Sheets.
See attached image:
EDIT:
Here is a google sheet that has some example data, and explanatory notes: https://docs.google.com/spreadsheets/d/1t0XImtjP4RKeTdg3L97bjPzateUX2waHPhjf3nmSFIk/edit#gid=2100307022
in GS try:
=FILTER(B3:C24; A3:A24="Period")
update
B15:
=SORT(B4:C12)
B25:
=QUERY({C15:C23, B16:B24}, "where Col1 is not null and Col2 is not null")
Here is the solution i created (working in both Excel + Google Sheets) for cutting downtimes from a time period, to leave only the remaining uptimes.
Using the same cells and ranges as per the Question....
The original downtimes does not need to be in order, they are sorted in the intermediate table.
in cell B15:
=IFERROR(SORT(FILTER(B4:C12,(B4:B12<=C3)*(C4:C12>=B3))),"")
Then, create named ranges for the elements to be used in the formulas that will populate the remaining uptimes (this makes the formulas easier to edit as will be noted below):
start is the start time of the original time period (B14)
end is the end time of the original time period (C14)
downstart is the range of the start datetimes of the downtimes (B15:B23)
downend is the range of the end datetimes of the downtimes (C15:C23)
Then, to create/populate the list of the remaining uptimes, for the opening times, enter this formula into the first cell (B25) :
=IFERROR(IF((start>=MIN(downstart))*(end<=MAX(downend)),IF(ROW()=(25+SUMPRODUCT(--(LEN(downstart)>0))-1),"",SMALL(downend,1+ROW()-25)),
IF((start>=MIN(downstart)),SMALL(downend,1+ROW()-25),
IF((end<=MAX(downend)),IF(ROW()=25,start,IF(ROW()=(25+SUMPRODUCT(--(LEN(downstart)>0))),"",SMALL(downend,ROW()-25))),
IF(ROW()=25,start,SMALL(downend,ROW()-25))
))),"")
And for the ending times, enter this formula into the first cell (C25):
=IFERROR(IF((start>=MIN(downstart))*(end<=MAX(downend)),IF(ROW()=(25+SUMPRODUCT(--(LEN(downend)>0))-1),"",SMALL(downstart,2+ROW()-25)),
IF((start>=MIN(downstart)),IF(ROW()=(25+SUMPRODUCT(--(LEN(downend)>0))-1),end,SMALL(downstart,2+ROW()-25)),
IF((end<=MAX(downend)),IF(ROW()=(25+SUMPRODUCT(--(LEN(downend)>0))-1),end,SMALL(downstart,1+ROW()-25)),
IF(ROW()=(25+SUMPRODUCT(--(LEN(downend)>0))),end,SMALL(downstart,1+ROW()-25))
))),"")
Note: In both of these formulas, the number 25 is the row number of the first row where the results are to be populated, so if you have these results starting on a different row, just change the number 25 to your starting row. Due to use of named ranges, no other changes are necessary.
After entering the formulas, drag them both down to fill the remaining results.
For those with Excel 2019 or newer (or Google Sheets), you can use IFS instead. For the opening times, use this (in B25 ):
=IFERROR(IFS(
(start>=MIN(downstart))*(end<=MAX(downend)),(IF(ROW()=(25+SUMPRODUCT(--(LEN(downstart)>0))-1),"",SMALL(downend,1+ROW()-25))),
(start>=MIN(downstart)),SMALL(downend,1+ROW()-25),
(end<=MAX(downend)),(IF(ROW()=25,start,IF(ROW()=(25+SUMPRODUCT(--(LEN(downstart)>0))),"",SMALL(downend,ROW()-25)))),
(start<MIN(downstart))*(end>MAX(downend)),(IF(ROW()=25,start,SMALL(downend,ROW()-25)))
),"")
And, for the ending times use this (in C25):
=IFERROR(IFS(
(start>=MIN(downstart))*(end<=MAX(downend)),(IF(ROW()=(25+SUMPRODUCT(--(LEN(downend)>0))-1),"",SMALL(downstart,2+ROW()-25))),
(start>=MIN(downstart)),(IF(ROW()=(25+SUMPRODUCT(--(LEN(downend)>0))-1),end,SMALL(downstart,2+ROW()-25))),
(end<=MAX(downend)),(IF(ROW()=(25+SUMPRODUCT(--(LEN(downend)>0))-1),end,SMALL(downstart,1+ROW()-25))),
(start<MIN(downstart))*(end>MAX(downend)),(IF(ROW()=(25+SUMPRODUCT(--(LEN(downend)>0))),end,SMALL(downstart,1+ROW()-25)))
),"")
Again, drag them down to populate the remaining results.
Explanation:
(IF(ROW()=(25+SUMPRODUCT(--(LEN(downend)>0))-1),xxxxxx styled sections of the formulas check if on certain row, so that can return specific results
SMALL(named_range,ROW()-(25)) styled sections of the formulas uses the ROW with an offset (25, based on this examples starting row for the results) to increment the SMALL
Both the nested IF and the IFS styled solutions are in the example file linked in the opening Question.

How to get the sum of values of a column in tmap?

I have 2 columns - Matches(Integer), Accounts_type(String). And i want to create a third column where i want to get proportions of matches played by different account types. I am new to Talend & am facing issue with this for past 2 days & did a lot of research but to no avail. Please help..
You can do it like this:
You need to read your source data twice (I used tFixedFlowInput_1 and tFixedFlowInput_2 with the same data). The idea is to calculate the total of your matches in tAggregateRow_1, it simply does a sum of all Matches without a group by column, then use that as a lookup.
The tMap then joins your source data with the calculated total. Since the total will always be one record, you don't need any join column. You then simply divide Matches by Total as required.
This is supposing you have unique values in Account_type; if you don't, you need to add another tAggregateRow between your source and tMap_1, in order to get sum of Matches for each Account_type (group by Account_type).

Linq to SQL - Random Select Order and Paging

We have a database with 2,00,000 vendor in 100 plus category, if someone visit the website we want to allow them to select a category and show them 25 Vendor per page, first we kept order by VendorId but it always use to get first 25, but we removed it, but now in paging it sometime repeat the vendor, is there a way to get random 25 vendor and also keep the paging.
Regards
you can randomize your result but everytime you dot he query, it will create new random list so unless you randomize and save the randomized state in your Code and page over it, it cant be done straightforward way.
refer, SQL Query results pagination with random Order by in SQL Server 2008
I believe this requirement is impossible to implement if a new random order is needed every time, there needs to be good performance and every item should have equal chance to get selected. I believe you should redesign the way your application works.
One possible workaround is to have a couple of columns in a table and fill them with random numbers. When a user requests the list assign the random column to him (stick it in the URL for example). Then do an order by that column and display the results. Randomly switch 4-5 columns to create the appearance of randomness. Update the random numbers in the columns once a day.

Yahoo Pipes Only One Item per Hour

Hello I'm building a Yahoo Pipe to feed my Facebook Fanpage. I have plenty of RSS Feeds which stream pictures and I want to limit the output to one picture per hour. But I'm completely new to pipes and can't find an understandable tutorial. Pipe looks like that
RSS1 RSS2 ... RSSn
| | |
+-----UNION----+
|
PIPE OUTPUT
You can do that using this algorithm:
Create a new field that contains the date truncated to hours
Use the Unique operator on this new field to get only one item per hour
You could implement this using pipes like this:
Copy pubDate to, say, datepart, using a Rename operator, with params:
item.pubDate
Copy As
datepart
Truncate datepart, using a Regex operator, with params:
In = item.datepart
replace = ^(.{13}).*
with = $1
That is, since date fields are represented as YYYY-mm-DDTHH:MM:ssZ we take the first 13 characters to get the date part up until the hour and discard the rest. For example if pubDate was 2013-11-03T13:34:37 then we get 2013-11-03T13.
Use a Unique operator based on item.datepart to filter items
As a simple demo, I put together a pipe for you that shows 1 question per month tagged yahoo-pipes on stackoverflow:
http://pipes.yahoo.com/pipes/pipe.info?_id=72fea3931e145324f308f0d5f6852d93
Note that you will get different results depending on where you put these elements. For example, you could put this logic after your union, to get one image per hour from all your source feeds combined. Or you could put this logic before your union, to get one image per hour per feed.
You might also ask, in case of multiple images per hour, which one will be picked? The first one. I think the default ordering is by pubDate. To make Yahoo Pipes pick a different item, insert an appropriate Sort operator before Unique.

Resources