Data structure for Matrix lookup in ruby, rails - ruby-on-rails

i want to use a matrix type data structure for storing and looking up values.
for this 2d array can be used. but i am looking for a better structure.
Requirements:
Matrix columns are fixed, but rows can increase.
for e.g.
see the following structure.
Issue| col1, col2, col3, col4
1 | 0, 1, 0, 0
2 | 0, 1, 0, 1
3 | 1, 1, 0, 0
[values in the structure are used as flag or status field]
now i want this structure to be used for look up
say i want to know the value for issue 2 col1 (which is 0 in above example)
what can be the better structure in ruby for the above scenario?
comments please?

What about a hash?
h = { 1 => [0,1,0,0],
2 => [0,1,0,1],
3 => [1,1,0,0] }
#fetch value for issue 2 col 1
puts h[2][0]

In case your data set is large and you want to have faster lookups and a more flexible design (what happens if you'll add a column later as your design evolves?), you might consider an in-memory database like supermodel. That way, you can avoid reinventing the wheel and you gain a lot of functionality and flexibility with very little effort.

Related

Google Sheets Combining Like Dice Rolls (While removing Integers)

My apologies for asking an incomplete question previously.
This is what I'm trying to accomplish.
I'm building a TTRPG sheet that automatically combines dice rolls, bonuses (additive) and penalties (subtractive) from a variety of sources. All of this data is expressed as either dice notation (D4, D6, D8, D10, D12, D20, and D100) or an Integer (1, 2, 4, 6), or both (combined). These also include negative values (-1D4, -1D6, -2, etc.). The goal isn't to generate the random numbers, but instead combine like dice together for the player to roll manually (I tried the automatic random numbers... Players were not happy about it.)
So, the goal is to combine likes, so something like:
"1D6+1D6" would become "2D6". However, because penalties could outweigh the bonus, you can't combine "1D6+1D6+-1D6" into "1D6". (Since each of the rolls could be a different number, such as "6+6-1" compared to "1+1-6").
Additionally, Integers (2, 4, 6, 8, etc.) are by necessity handled in a different part of the sheet, so the goal is to strip the integers out from the output. (The reason for stripping them out has nothing to do with formula complexity, but other game factors that require it to be viewed separately.)
Here are some examples of typical inputs and expected outputs:
1D6+1D4+1D8+-1D4+1D6+2 = 1D4+-1D4+2D6+1D8 (Notice the integer is removed)
1D6+2+0+1+8 = 1D6 (Because all integers have been stripped out)
1D20+-1D4+2D6+0+1D6+-1D6 = +-1D4+3D6+-1D6+1D20
(Yes, negative numbers will have the "+-" in front of them).
My original "mostly working" formula was 2 solid pages long when copied/pasted into MS Word. This formula will be repeated THOUSANDS of times, so smaller/faster makes a huge difference in the overall scheme of things. Two previous amazing Spreadsheet Wizards (Player0 and TheMaster) gave great answers, but I failed to disclose the integer as a part of the overall process.
The table below shows the formula that works for the first example, but not the second (gives "2D" in the output).
For original explanation, see Google Sheets Formula for combining dice rolls
After the first split by +, check if the result is a TEXT and if not, FILTER it out:
=JOIN("+",BYROW(QUERY(REDUCE({"",""},SEQUENCE(2),LAMBDA(a,c,{a;QUERY({ARRAYFORMULA(SPLIT(TRANSPOSE(LAMBDA(ar,FILTER(ar,ISTEXT(ar)))(SPLIT(B1,"+"))),"D"))}," select sum(Col1),Col2 where Col1"&IF(c=1,">","<")&"0 group by Col2 label sum(Col1) ''")})),"order by Col2"),LAMBDA(r,JOIN("D",r))))
For no negative values, add a empty array {"",""} for NA:
=JOIN("+",BYROW(QUERY(REDUCE({"",""},SEQUENCE(2),LAMBDA(a,c,{a;IFNA(QUERY({ARRAYFORMULA(SPLIT(TRANSPOSE(LAMBDA(ar,FILTER(ar,ISTEXT(ar)))(SPLIT(B1,"+"))),"D"))},"select sum(Col1),Col2 where Col1"&IF(c=1,">","<")&"0 group by Col2 label sum(Col1) ''"),{"",""})})),"where Col1 is not null order by Col2"),LAMBDA(r,JOIN("D",r))))
try:
=INDEX(REGEXREPLACE(TEXTJOIN("+", 1, FLATTEN(QUERY(TRANSPOSE(QUERY(QUERY(IFERROR(IFNA(TRANSPOSE({
REGEXEXTRACT(SPLIT(C5, "+"), "^\d+")*1; REGEXEXTRACT(SPLIT(C5, "+"), "D\d+");
REGEXEXTRACT(SPLIT(C5, "+"), "^-\d+")*1; REGEXEXTRACT(SPLIT(C5, "+"), "D\d+");
REGEXEXTRACT(SPLIT(C5, "+"), "D(\d+)")*1}), 0)),
"select sum(Col1),Col2,'+',sum(Col3),Col4,Col5
where Col2 is not null group by Col2,Col4,Col5 order by Col5"),
"select Col1,Col2,Col3,Col4,Col5 offset 1", )),,9^9))), " |\+ 0 D\d+", ))

How to pull data from every third column using QUERY function

I am using this formula but the same formula needs to be applied to every third column. ie: starting from D3:D, G3:G, J3:J, and so on... what is the best way to apply or pull the data from every third column. (data is on the second sheet called Sitemap)
Please advise and help, many many thanks much appreciated!
=query({
'Sitemaps'!D3:D1000},
"Select * where Col1 is not null ")
Adding the sheet link maybe that will be more helpful to understand the situation, "AllURLs" needs to pull all links from Sitemaps into one list
https://docs.google.com/spreadsheets/d/1AWGfA7cHmF3Q2kiX1xkQcoec6H5EPiHUXaiWENMzZkA/edit?usp=sharing
use:
=QUERY({INDIRECT("Sitemaps!"&
ADDRESS(3, (COLUMN($D1)-1)*COLUMN(A1)+1)&":"&
ADDRESS(1000, (COLUMN($D1)-1)*COLUMN(A1)+1))},
"where Col1 is not null")
and drag to the right
update:
use in B3:
=INDEX(IFERROR(REGEXEXTRACT(C3:C,"^(?:https?:\/\/)?(?:www\.)?([^\/]+)")))
use in C3:
=QUERY(FLATTEN(FILTER(IFERROR(Sitemaps!D3:1000), MOD(COLUMN(Sitemaps!D1:1)-1, 3)=0)),
"where Col1 is not null")
Try this:
=FILTER(FILTER(Sitemaps!D3:J,MOD(COLUMN(Sitemaps!D3:J)-4,3)=0),Sitemaps!D3:D<>"")
Just replace :J with whichever column is further to the right in your data set.
This one formula should produce all results, assuming that any rows that have data in Column D also have data in that row of every other included column, and that rows that are null in Column D are also null in that row of every other included column.
MOD is the modulus function. It returns whatever is left after dividing a number by another number. For instance, MOD(7,3) would return 1, because 7 divided by 3 is 6 with 1 left over. The leftover portion is the modulus.
We can apply this to your column numbers, since the ones you want to retrieve are evenly spaced three apart. We just need to start at a baseline of zero. Since Column D has a column number of 4, we can "zero out" that baseline by subtracting 4 from every column number. Only those columns that then are evenly divisible by 3 (i.e., those that, after subtracting 4, have a modulus of 0) are returned.

Converting formula to ARRAYFORMULA issues with SUM and INDEX

I have a scoring spreadsheet for a competition I'm working on. Competitors' place/rank are converted into points towards the overall series based on a chart of corresponding values. For ties, the sum of the points covered by all of the tied places are split evenly among the tied competitors (i.e. 2-way tie for 3rd; if 3rd usually gets 10 points and 4th usually gets 8, these competitors will receive (10+8)/2 (2 being the # of tied competitors), so they each receive 9 points).
I have a formula which does this exact calculation:
=IFERROR(IF(ISBLANK($A4:$A),,SUM(INDEX(SeriesPoints, E4:E):INDEX(SeriesPoints, MIN(E4:E + COUNTIF(E$4:E, E4:E) - 1, ROWS(SeriesPoints)))) / COUNTIF(E$4:E, E4:E), 0))
Where 'SeriesPoints' is a 2 column array; column 1 is the places/ranks (1:125) and column 2 is their corresponding point values. Column 'E' is the competitors' rank from the competition.
I have been unable to convert this formula to an ARRAYFORMULA() so I can avoid dragging it down the entire sheet (possibly up to 1000+ competitors over the series).
I'm mildly proficient with MMULT(), so I understood that would be a good approach for switching out SUM(), however, I haven't been able to create a matrix of the values to be summed.
INDEX():INDEX() doesn't work with ARRAYFORMULA() so I've tried switching to VLOOKUP(). With VLOOKUP() I've been able to produce the start and end values of the range of values for a tie, but not the full list. For example, if there is a 3-way tie for 4th, I can produce the respective points for 4th and 6th (the bounds of the tie).
In an attempt to list out even just the numbers from 4:6, I've hit a wall converting what would be a simple ROW() or SEQUENCE() formula to a matrix/array.
The following formula produces an array of the upper and lower bounds of ties or the single place should there be no tie, although the single place gets repeated.
=ARRAYFORMULA(IF(COUNTIF(E$4:E,E4:E)=1,E4:E,{E4:E,E4:E+COUNTIF(E$4:E,E4:E)-1}))
I'm assuming if I can get VLOOKUP({#:#}) to fill properly, I'll be where I need to be.
From here, I feel confident in my abilities to wrap a VLOOKUP() for the actual point values, an MMULT() to sum across these rows for the total, then a simple division to produce the correct point value.
Spreadsheet: https://docs.google.com/spreadsheets/d/1lpNewR3p4i7ZHmlFGLlG1tLuxgO-6onSeH8mWTeclBw/edit?usp=sharing
Currently, my workspace is off to the right. The original formula is in F4 and my test codes are working on column G instead of E.
So for sample placements of 1,1,3,3,3,6,7,8 and sample points values of 1000, 850,738,663,633,603,573,550 I expect the output to be 925 for the two 1st place tied competitors, 678 for the tied 3rd places, 603 for 6th, 573 for 7th, and 550 for 8th.
I'd appreciate any and all help!
=ARRAYFORMULA(IFERROR(IFERROR(VLOOKUP(G4:G, QUERY({INDIRECT("G4:G"&counta(A4:A)+3),
VLOOKUP(ROW(INDIRECT("A1:A"&COUNTA(A4:A))), SeriesPoints, 2, 0)},
"select Col1,sum(Col2) group by Col1 label sum(Col2)''", 0), 2, 0))/
IFERROR(VLOOKUP(G4:G, QUERY(G4:G,
"select G,count(G) where G is not NULL group by G label count(G)''", 0), 2, 0))))

Google Sheet Split One Column Into Array [duplicate]

Simply put I am trying to take a single column query result and output it into a 5 wide by × long table. This is how the main table is organized.
On separate tabs, I want to list all of the caught and seen Pokemon on their own for easy search. While I can get it to output something like this with
=query(NatDex, "Select C Where F <> ''",1)
I would like it to output the data something like this for easy reading so it's not eventually 100+ entries long:
Bonus points if you can give me formula/something to do it where I can vary how wide the second table is. But this is far less important to me. I've tried looking up stuff like Pivot tables or Transpose, but neither of them seems to have the functions I need to pull this off.
if you put your query output in some auxiliary column, you can use this formula and drag down:
=ARRAY_CONSTRAIN(TRANSPOSE(INDIRECT("A"&6+(ROW()-ROW($A$2))*5&":A")), 1, 5)
for 6 columns:
=ARRAY_CONSTRAIN(TRANSPOSE(INDIRECT("A"&7+(ROW()-ROW($A$2))*6&":A")), 1, 6)
for 3 columns:
=ARRAY_CONSTRAIN(TRANSPOSE(INDIRECT("A"&4+(ROW()-ROW($A$2))*3&":A")), 1, 3)
for 5 columns but starting on 10th row:
=ARRAY_CONSTRAIN(TRANSPOSE(INDIRECT("A"&6+(ROW()-ROW($A$2)-9)*5&":A")), 1, 5)
etc.

Query one table and output data into multiple columns

Simply put I am trying to take a single column query result and output it into a 5 wide by × long table. This is how the main table is organized.
On separate tabs, I want to list all of the caught and seen Pokemon on their own for easy search. While I can get it to output something like this with
=query(NatDex, "Select C Where F <> ''",1)
I would like it to output the data something like this for easy reading so it's not eventually 100+ entries long:
Bonus points if you can give me formula/something to do it where I can vary how wide the second table is. But this is far less important to me. I've tried looking up stuff like Pivot tables or Transpose, but neither of them seems to have the functions I need to pull this off.
if you put your query output in some auxiliary column, you can use this formula and drag down:
=ARRAY_CONSTRAIN(TRANSPOSE(INDIRECT("A"&6+(ROW()-ROW($A$2))*5&":A")), 1, 5)
for 6 columns:
=ARRAY_CONSTRAIN(TRANSPOSE(INDIRECT("A"&7+(ROW()-ROW($A$2))*6&":A")), 1, 6)
for 3 columns:
=ARRAY_CONSTRAIN(TRANSPOSE(INDIRECT("A"&4+(ROW()-ROW($A$2))*3&":A")), 1, 3)
for 5 columns but starting on 10th row:
=ARRAY_CONSTRAIN(TRANSPOSE(INDIRECT("A"&6+(ROW()-ROW($A$2)-9)*5&":A")), 1, 5)
etc.

Resources