Grade Up/Down APL order - terminology

How come that
⌽(⍒'Hello')
is
1 2 4 3 5
when
⍋'Hello'
is
1 2 3 4 5
?
I'm new to APL and stumbled on it by accident. I just wonderes why the second l comes before the first.

You are using both the grade up ⍋ and grade down ⍒ as monadic primitives.
By definition grade up returns an integer array of indices which specify the sorted order of the expression following it, in ascending order. If any elements are equal (in your example the two letter l's) , they will appear in the result in the same order that they appeared in the input expression.
So, ⍋'Hello' returns 1 2 3 4 5. The two l's are in the same order, i.e., the 3rd character (1st letter l) precedes the 4th character (2nd letter l).
By definition grade down also returns an integer array of indices which specify the sorted order of the expression following it, in descending order. If any elements are equal (in your example the two letter l's) , they will also appear in the result in the same order that they appeared in the expression.
So, ⍒'Hello' returns 5 3 4 2 1. The two l's remain in the same order because they are equal.
When you apply rotate ⌽ the integer array gets reversed to 1 2 4 3 5 as you witnessed.
The outcome you are seeing is precisely what is expected given the way the functions are defined and how they deal with equal values.
If you want to see a more extreme example compare the output for the following two arrays. Create an array with 10 elements each having the same value of 1. 10⍴1 and then try the grade up function and then try the grade down function:
⍋10⍴1
and
⍒10⍴1
They will both yield the same result:
1 2 3 4 5 6 7 8 9 10

The grade up ⍋ and grade down ⍒ primitives preserve the order of equal elements. As others have said, there must be a rule for equal arguments. But this rule has the virtue that it allows multi-key sorts.
That is, if you have an array with several associated keys, by sorting on each key from least significant to most significant, you obtain a result sorted by the most significant key, with equals sorted by the 2nd mot significant, items equal on the 1st two sorted by the 3rd, and so on. For this to work the index vector must be captured and used to update all keys and the data to keep them in sync. Or they could be stored in a nested structure, in which case they would automatically be kept in proper relative order.

Related

Update a row if a field is a subsequence of a string

I have a string S = "1-2-3-4-5-6-7-8"
This is how my database table rows look like:
id
SubSequence
1
1-2-4-5
2
1-3-4-5
3
2-5-7-8
4
5-8-9-10
5
6-7-10-11
and so on ...
I want to write a query that would update (in this example) only the first 3 rows because they're a subsequence of string S.
The current solution I have is to programmatically go thru each row, check if it's a subsequence, and update. But I'm wondering if there's a way to do it at the MySQL level for performance.
Update: I don't mind changing the way data is stored. For example, String S could be an array holding those numbers, and the "SubSequence" column can hold those numbers as an array.
No, there is not a way to do the query you describe with good performance in SQL when you store the subsequences as strings like you have done. The reason is that doing substring comparisons cannot be optimized with indexes, so your query will be forced to do the comparisons row by row.
In general, when you try to store sets of values as a string, but you want to use SQL to treat them as discrete values, it's bound to be awkward, difficult to code, and ultimately have bad performance.
In this case, what I would do is make a two tables, one that numbers your entities, and a second table in which each value in your subsequence is stored on a row by itself.
SubSequences:
id
1
2
SubSequenceElements:
id
SubSequenceElement
1
1
1
2
1
4
1
5
2
1
2
3
2
4
2
5
And so on.
Then you can use relational-division techniques to find cases where every element of this set exists in the set you want to compare it to.
Here's an example:
SELECT s.id
FROM SubSequences AS s
LEFT OUTER JOIN (
SELECT id
FROM SubSequenceElements
WHERE SubSequenceElement NOT IN (1,2,3,4,5,6,7,8)
) AS invalid USING (id)
WHERE invalid.id IS NULL;
In other words, you want to return rows from SubSequences such that no match is found in SubSequenceElements with an element value that is not in the set you're trying to match.
It's a bit confusing, because you have to think about the problem is a double-don't-match-this-set problem. But once you get relational division, it can be very powerful.
If the set can be represented by the numbers 0 through 63 (or some subset of that), then...
Using a column like this
elements BIGINT UNSIGNED NOT NULL DEFAULT '0'
Then "2-5-7-8" could be put into it thus:
UPDATE ...
SET elements = (1<<2) | (1<<5) | (1<<7) | (1<<8);
Then various operations can be done in a single expression:
WHERE elements = (1<<2) | (1<<5) | (1<<7) | (1<<8) -- Test for exactly that set
WHERE (elements ^ ~ ( (1<<2) | (1<<5) | (1<<7) | (1<<8) )) != 0
-- checks to see if any other bits are turned on
This last example is close to what you need. One side of the "and not" would have the 1..8 of your example, the other would have
Your example has S represented as 0x1FE;
WHERE subsequence & ~0x1FE
will be 0 (false) for ids 1,2,3; non-zero (true) for ids 4 and 5.

Need a different permutation of groups of numbers

I have numbers from 1 to 36. What I am trying to do is put all these numbers into three groups and works out all various permutations of groups.
Each group must contain 12 numbers, from 1 to 36
A number cannot appear in more than one group, per permutation
Here is an example....
Permutation 1
Group 1: 1,2,3,4,5,6,7,8,9,10,11,12
Group 2: 13,14,15,16,17,18,19,20,21,22,23,24
Group 3: 25,26,27,28,29,30,31,32,33,34,35,36
Permutation 2
Group 1: 1,2,3,4,5,6,7,8,9,10,11,13
Group 2: 12,14,15,16,17,18,19,20,21,22,23,24
Group 3: 25,26,27,28,29,30,31,32,33,34,35,36
Permutation 3
Group 1: 1,2,3,4,5,6,7,8,9,10,11,14
Group 2: 12,11,15,16,17,18,19,20,21,22,23,24
Group 3: 25,26,27,28,29,30,31,32,33,34,35,36
Those are three example, I would expect there to be millions/billions more
The analysis that follows assumes the order of groups matters - that is, if the numbers were 1, 2, 3 then the grouping [{1},{2},{3}] is distinct from the grouping [{3},{2},{1}] (indeed, there are six distinct groupings when taking from this set of numbers).
In your case, how do we proceed? Well, we must first choose the first group. There are 36 choose 12 ways to do this, or (36!)/[(12!)(24!)] = 1,251,677,700 ways. We must then choose the second group. There are 24 choose 12 ways to do this, or (24!)/[(12!)(12!)] = 2,704,156 ways. Since the second choice is already conditioned upon the first we may get the total number of ways of taking the three groups by multiplying the numbers; the total number of ways to choose three equal groups of 12 from a pool of 36 is 3,384,731,762,521,200. If you represented numbers using 8-bit bytes then to store every list would take at least ~3 pentabytes (well, I guess times the size of the list, which would be 36 bytes, so more like ~108 pentabytes). This is a lot of data and will take some time to generate and no small amount of disk space to store, so be aware of this.
To actually implement this is not so terrible. However, I think you are going to have undue difficulty implementing this in SQL, if it's possible at all. Pure SQL does not have operations that return more than n^2 entries (for a simple cross join) and so getting such huge numbers of results would require a large number of joins. Moreover, it does not strike me as possible to generalize the procedure since pure SQL has no ability to do general recursion and therefore cannot do a variable number of joins.
You could use a procedural language to generate the groupings and then write the groupings into a database. I don't know whether this is what you are after.
n = 36
group1[1...12] = []
group2[1...12] = []
group3[1...12] = []
function Choose(input[1...n], m, minIndex, group)
if minIndex + m > n + 1 then
return
if m = 0 then
if group = group1 then
Choose(input[1...n], 12, 1, group2)
else if group = group2 then
group3[1...12] = input[1...12]
print group1, group2, group3
for i = i to n do
group[12 - m + 1] = input[i]
Choose(input[1 ... i - 1].input[i + 1 ... n], m - 1, i, group)
When you call this like Choose([1...36], 12, 1, group1) what it does is fill in group1 with all possible ordered subsequences of length 12. At that point, m = 0 and group = group1, so the call Choose([?], 12, 1, group2) is made (for every possible choice of group1, hence the ?). That will choose all remaining ordered subsequences of length 12 for group2, at which point again m = 0 and now group = group2. We may now safely assign group3 to the remaining entries (there is only one way to choose group3 after choosing group1 and group2).
We take ordered subsequences only by propagating the index at which to begin looking on the recursive call (minIdx). We take ordered subsequences to avoid getting permutations of the same set of 12 items (since order doesn't matter within a group).
Each recursive call to Choose in the loop passes input with one element removed: precisely that element that just got added to the group under consideration.
We check for minIndex + m > n + 1 and stop the recursion early because, in this case, we have skipped too many items in the input to be able to ever fill up the current group with 12 items (while choosing the subsequence to be ordered).
You will notice I have hard-coded the assumption of 12/36/3 groups right into the logic of the program. This was done for brevity and clarity, not because you can't make parameterize it in the input size N and the number of groups k to form. To do this, you'd need to create an array of groups (k groups of size N/k each), then call Choose with N/k instead of 12 and use a select/switch case statement instead of if/then/else to determine whether to Choose again or print. But those details can be left as an exercise.

Summing Columns up with some exceptions

I am working on a database with two different tables.
The first contains every change in the database like a transaction table. It contains the object that was bought/sold, how many of them where bought/sold, when this tranaction happend and in which place.
The second table contains the total value of every object that should be available in those places.
Now here is my question:
I want to automaticly sum up every entry with the same object and location inside of table one and save this value inside of table two.
BUT
Sometimes there are special entrys in table one which should not be summed up with the other values. They should overwrite the value.
I have an example of how this summing up should look like:
n = normal value, s = special value
n: 1 sum: 1
n: 2 sum: 3
s: 7 sum: 7
n: 5 sum: 12
n: 4 sum: 16
n: 7 sum: 23
s: 20 sum: 20
To help you help me I have some additional informations:
There are 4 columns inside of table one
The first one is called object and contains the object number for which this entry takes effect.
The second column contains the amount of that object. Whether it was bought or sold.
The third column tells me on which locations this transaction belongs to. Which also means that every object has different amounts depending on the location.
The fourth column contains an information why this transaction happend. It tells me if this transaction happend because I bought something or because I sold something OR because I counted my stock.
This is the special indicator which should tell my database not to sum up this value but instead overwrite the previous one with this.
The fifth and last column contains the date when this transaction happend. This is very important because the whole table is sorted by the date. And it tells when those special values come in place.
The other table just contains the summed up value for every object in every location.
This below will return the sum of each record for a particular Object 'MyObj' starting from the last instance of a 'Special' entry (inclusive).
(Untested)
SELECT Sum(a.Amount) AS TheSum
FROM tblMyTable a
WHERE ID_PK> = nz((
SELECT max(ID_PK)
FROM tblMyTable
WHERE Object=a.Object AND IsSpecial=1
),0)
AND a.Object='MyObj'

RowNumber for group in SSRS 2005

I have a table in a SSRS report that is displaying only a group, not the table details. I want to find out the row number for the items that are being displayed so that I can use color banding. I tried using "Rowcount(Nothing)", but instead I get the row number of the detail table.
My underlying data is something like
ROwId Team Fan
1 Yankees John
2 Yankees Russ
3 Red Socks Mark
4 Red Socks Mary
...
8 Orioles Elliot
...
29 Dodgers Jim
...
43 Giants Harry
My table showing only the groups looks like this:
ROwId Team
2 Yankees
3 Red Socks
8 Orioles
29 Dodgers
43 Giants
I want it to look like
ROwId Team
1 Yankees
2 Red Socks
3 Orioles
4 Dodgers
5 Giants
You can do this with a RunningValue expression, something like:
=RunningValue(Fields!Team.Value, CountDistinct, "DataSet1")
DataSet1 being the name of the underlying dataset.
Consider the data:
Creating a simple report and comparing the RowNumber and RunningValue approaches shows that RunningValue gives your required results:
You can easily achieve this with a little bit of vbcode. Go to Report - Properties - code and type something like:
Dim rownumber = 0
Function writeRow()
rownumber = rownumber + 1
return rownumber
End Function
Then on your cell, call this function by using =Code.writeRow()
As soon as you start using groups inside the tables, the RowNumber and RunningGroup functions start getting some weird behaviours, thus it's easier to just write a bit of code to do what you want.
I am not convinced all suggestions above provide are a one for all solution. My scenario is I have a grouping that has has multiple columns. I could not use the agreed solution RunningValue because I don't have a single column to use in the function unless I combine (say a computed column) them all to make single unique column.
I could not use the VBA code function as is for the same reason and I had to use the same value across multiple columns and multiple properties for that matter unless I use some other kind of smarts where if I knew the number of uses (say N columns * M properties) then I could only update the RowNumber on every NxM calls however, I could not see any count columns function so if I added a column I would also need to increase my N constant. I also did not want to add a new column as also suggested to my grouping as I could not figure out how to hide it and I could not write a vba system where I could call function A that returns nothing but updates the value (i.e. called only once per group row) then call another function GetRowNumber which simply returns the rownumber variable because the colouring was done before the call so I always had one column out of sync to the rest.
My only other 2 solutions I could think of is put the combined column as mentioned earlier in the query itself or use DENSE_RANK and sort on all group columns, i.e.
DENSE_RANK() OVER (ORDER BY GroupCol1, GroupCol2, ...) AS RowNumber

Is there a possibility to change the order of a string with numeric value

I have some strings in my database. Some of them have numeric values (but in string format of course). I am displaying those values ordered ascending.
So we know, for string values, 10 is greater than 2 for example, which is normal. I am asking if there is any solution to display 10 after 2, without changing the code or the database structure, only the data.
If for example I have to display values from 1 to 10, I will have:
1
10
2
3
4
5
6
7
8
9
What I would like to have is
1
2
3
4
5
6
7
8
9
10
Is there a possibility to ad an "invisible character or string which will be interpreted as greater than 9". If i put a10 instead of 10, the a10 will be at the end but is there any invisible or less visible character for that.
So, I repeat, I am not looking for a programming or database structure solution, but for a simple workaround.
You could try to cast the value as an number to then order by it:
select col
from yourtable
order by cast(col AS UNSIGNED)
See SQL Fiddle with demo
You could try appending the correct number of zeroes to the front of the data:
01
02
03
..
10
11
..
99
Since you have a mixture of numbers and letters in this column - even if not in a single row - what you're really trying to do is a Natural Sort. This is not something MySQL can do natively. There are some work arounds, however. The best I've come across are:
Sort by length then value.
SELECT
mixedColumn
FROM
tableName
ORDER BY
LENGTH(mixedColumn), mixedColumn;
For more examples see: http://www.copterlabs.com/blog/natural-sorting-in-mysql/
Use a secondary column to use as a sort key that would contain some sort of normalized data (i.e. only numbers or only letters).
CREATE TABLE tableName (mixedColumn varchar, sortColumn int);
INSERT INTO tableName VALUES ('1',1), ('2',2), ('10',3),
('a',4),('a1',5),('a2',6),('b1',7);
SELECT
mixedColumn
FROM
tableName
ORDER BY
sortColumn;
This could get difficult to maintain unless you can figure out a good way to handle the ordering.
Of course if you were able to go outside of the database you'd be able to use natural sort functions from various programming languages.