How to insert element between other elements in KDB/Q list - kdb

Say I have a list (1 3 4) and after 1 I want to insert another element 2 resulting in (1 2 3 4).
How can this be done efficiently in a generic way?

An alternative approach which allows for multiple inserts at once.
If the indices are to index the original list:
q){raze cut[(0,z);x],'(y,enlist ())}[til 10;999 998 994;2 4 8]
0 1 999 2 3 998 4 5 6 7 994 8 9
If the indices are to index consecutive iterations of the list:
q){raze cut[(0,z);x],'(y,enlist ())}/[til 10;999 998 994;2 4 8]
0 1 999 2 998 3 4 5 994 6 7 8 9

I think you need to be more specific about what you want, but for now here's an example of how you could achieve it
q)list:1 3 4
q)list
1 3 4
q)list: asc list,:2
q)list
`s#1 2 3 4
Or another way is let's say you know the index at which you want to add the element to the list, in this case at index 1, then you could create a function as such:
q)add:{[lst;ele;ind] (ind#lst),ele,(ind _ lst)}
q)list:1 3 4
q)add[list;2;1]
1 2 3 4

Related

Sorting two columns of a matrix while keeping one intact in OCTAVE/MATLAB

I have this matrix:
data=[1 5402783 1
2 43359352 2
3 26118700 3
4 33091887 4
5 890931 5
6 826897 6
7 1188749 7
8 1239861 8];
I need the first column to stay as it is, sort the 2nd column (in descending order) and 'keep along' the values of the third column. If I use sort(data) it sorts all 3 columns.
I tried:
[~,idx]=sort(data(:,2),'descend');
data=data(idx,:)
but it is obviously wrong.
The output should be:
[1 43359352 2
2 33091887 4
3 26118700 3
4 5402783 1
5 1239861 8
6 1188749 7
7 890931 5
8 826897 6]
All you need to do is reassemble the data matrix in the end taking the unsorted and sorted parts:
data = [1 5402783 1
2 43359352 2
3 26118700 3
4 33091887 4
5 890931 5
6 826897 6
7 1188749 7
8 1239861 8];
[~,idx] = sort(data(:,2),'descend');
data = [data(:,1),data(idx,2:3)];

KDB+/Q:Input agnostic function for single and multi row tables

I have tried using the following function to derive a table consisting of 3 columns with one column data holding a list of an arbitrary schema.
fn:{
flip `time`data`id!(x`b;(x`a`b`c`d`e);x`a)
};
which works well on input with multiple rows i.e.:
q)x:flip `a`b`c`d`e!(5#enlist 5?10)
q)fn[`time`data`id!(x`b;(x`a`b`c`d`e);x`a)]
time data id
-----------------
8 8 5 2 8 6 8
5 8 5 2 8 6 5
2 8 5 2 8 6 2
8 8 5 2 8 6 8
6 8 5 2 8 6 6
However fails when using input with a single row i.e.
q)x:`a`b`c`d`e!5?10
q)fn[`time`data`id!(x`b;(x`a`b`c`d`e);x`a)]
time data id
------------
8 7 7
8 8 7
8 4 7
8 4 7
8 6 7
which is obviously incorrect.
One might fix this by using enlist i.e.
q)x:enlist `a`b`c`d`e!5?10
q)fn[`time`data`id!(x`b;(x`a`b`c`d`e);x`a)]
time| 8
data| 7 8 4 4 6
id | 7
Which is correct, however if one were to apply this in the function i.e.
fn:{
flip enlist `time`data`id!(x`b;(x`a`b`c`d`e);x`a)
};
...
time| 2 5 8 7 9
data| 2 5 8 7 9 2 5 8 7 9 2 5 8 7 9 2 5 8 7 9 2 5 8 7 9
id | 2 5 8 7 9
Which has the wrong format of data values.
My question here is how might one avert this conversion issue and derive the same field values whether the argument is a multi row or single row table.
Or otherwise what is the canonical implementation of this in kdb+/q
Thanks
Edit:
To clarify: my problem isn't necessarily with the data input as one could just apply enlist if it is only one row. My question pertains to how one might use enlist in the fn function to make single row input conform to the logic seen when using multi row tables. i.e. how to replace fn enlist input with fn data (how to make the function input agnostic) Thanks
Are you meaning to flip the data perpendicular to the rest of the table? Your 5 row example works because there are 5 rows and 5 columns. The single row doesn't work due to 1 row to 5 columns.
Correct me if I'm wrong but I think this is what you want:
fn:{([]time:x`b;data:flip x`a`b`c`d`e;id:x`a)};
--------------------------------------------------
t1:flip `a`b`c`d`e!(5#enlist til 5);
a b c d e
---------
0 0 0 0 0
1 1 1 1 1
2 2 2 2 2
3 3 3 3 3
4 4 4 4 4
fn[t1]
time data id
-----------------
0 0 0 0 0 0 0
1 1 1 1 1 1 1
2 2 2 2 2 2 2
3 3 3 3 3 3 3
4 4 4 4 4 4 4
--------------------------------------------------
t2:enlist `a`b`c`d`e!til 5;
a b c d e
---------
0 1 2 3 4
fn[t2]
time data id
-----------------
1 0 1 2 3 4 0
Note without the flip you get this:
([]time:t1`b;data:t1`a`b`c`d`e;id:t1`a)
time data id
-----------------
0 0 1 2 3 4 0
1 0 1 2 3 4 1
2 0 1 2 3 4 2
3 0 1 2 3 4 3
4 0 1 2 3 4 4
In this case the time is no longer in line with the data but it works because of 5 row and cols.
Edit - I can't think of a better way to convert a dictionary to a table when needed other than using count first in a conditional. Note if the first key is a nested list this wouldn't work
{ $[1 = count first x;enlist x;x] } `a`b`c`d`e!til 5
Note, your provided function doesn't work with this:
{
flip `time`data`id!(x`b;(x`a`b`c`d`e);x`a)
}{$[1 = count first x;enlist x;x]} `a`b`c`d`e!til 5

How to implement combinations of a list

All
I need to get the combinations and permutations of a list.
A function have been implemented for permutations.
perm:{[N;l]$[N=1;l;raze .z.s[N-1;l]{x,/:y except x}\:l]}
However, I have no idea about combinations, just like this:
l: 1 2 3
comb[2;l]
1 2
1 3
2 3
l: 1 2 3 4
comb[3;l]
1 2 3
1 2 4
1 3 4
2 3 4
Thanks!
From your solution, you can do:
q)comb:{[N;l]$[N=1;l;raze .z.s[N-1;l]{x,/:y where y>max x}\:l]}
q)comb[2;1 2 3]
1 2
1 3
2 3
Another approach using over:
q)perm:{{raze x{x,/:y except x}\:y}[;y]/[x-1;y]}
q)comb:{{raze x{x,/:y where y>max x}\:y}[;y]/[x-1;y]}
One option is to use your permutation function like this:
q) comb:{[N;l] distinct asc each perm[N;l] }
q)l: 1 2 3 4
q) comb[3;l]
output:
1 2 3
1 2 4
1 3 4
2 3 4
Note: This will change the order of elements because of asc. So if your list should have (1 3 2) in answer, it will give (1 2 3).
To maintain order, use any other function/logic in place of asc to filter duplicate elements in sets (ex: (1 2 3) and (1 3 2) are duplicates).

How to get range of elements in a list in KDB?

For example, I have this list:
test:(8;12;15;19;10)
How may I select elements 2 to 4?
When I try list[2;4] it doesn't work for me.
indexing a list is by far the fastest way.
q)a
8 1 9 5 4 6 6 1 8 5 4 9 2 7 0 1 9 2 1 8 8 1 7 2 4 5 4 2 7 8 5 6 4 1 3 3 7 8 2..
q)\t do[100000;2 3 sublist a]
109
q)\t do[100000;a 2 3 4]
15
So just follow your list with a list of indexes. BTW you can create indexes with til
q)til 2
0 1
q)2+til 2
2 3
You can use sublist for this
test:(8;12;15;19;10);
2 3 sublist test
This will return three elements from the list starting at index 2.
As answered by Manish, til is the best bet here. You can define a simple function range using til to give the index range :
q)test:(8;12;15;19;10)
q)range:{x+til 1+abs[y-x]} //include the start and end index
q)test range[2;4]
15j, 19j, 10j

How to duplicate all inner columns of a matrix and sum pairs of columns in Matlab

Suppose I have a matrix A
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
How do I duplicate the inner columns of A to get a new matrix B
1 2 2 3 3 4 4 5
1 2 2 3 3 4 4 5
1 2 2 3 3 4 4 5
1 2 2 3 3 4 4 5
1 2 2 3 3 4 4 5
Notice the first and last column of A were left alone. Then I need to sum pairs of rows together to get another matrix C:
3 5 7 9
3 5 7 9
3 5 7 9
3 5 7 9
3 5 7 9
The size of my matrices will not always be 5x5 and the elements will not always be so nice, but the matrix will always be square.
I do not need to generate or output matrix B. That was just simply how I initially thought of obtaining my final matrix C.
My goal is to be reasonably efficient, so I would like to accomplish this without a for loop.
How do I accomplish this for arbitrary matrix size nxn ?
Very simple . .
C = A(:,2:end) + A(:,1:end-1)