How do I select a subset of an array in Postgres? - arrays

Assuming I have an array in one of my postgres columns:
> select array[1,2,3,4];
array
-----------
{1,2,3,4}
How do I select a subset of the items from that array, in general? For instance, if I want to select items from the x index to the y index, how would I grab the items in that range (x to y)?
I'm using PostgreSQL 9.4.

From the fine manual:
8.15.3. Accessing Arrays
[...]
We can also access arbitrary rectangular slices of an array, or subarrays. An array slice is denoted by writing lower-bound:upper-bound for one or more array dimensions.
[...]
It is possible to omit the lower-bound and/or upper-bound of a slice specifier; the missing bound is replaced by the lower or upper limit of the array's subscripts.
For example:
=> select (array[1,2,3,4,5,6])[2:5];
array
-----------
{2,3,4,5}
(1 row)
=> select (array[1,2,3,4,5,6])[:5];
array
-------------
{1,2,3,4,5}
(1 row)
=> select (array[1,2,3,4,5,6])[2:];
array
-------------
{2,3,4,5,6}
(1 row)
=> select (array[1,2,3,4,5,6])[:];
array
---------------
{1,2,3,4,5,6}
(1 row)
So to get a slice from index x to y (inclusive), you'd say:
array_column[x:y]

Related

construct a matrix by removing different elements from an array without loops in matlab

Given a vector X of discrete positive integers with size 160*1, and a table Tb1 in size 40*200, that contains a list of indices to be deleted from X Each column from the 200 columns in Tb1 points to 40 elements to be deleted from original X.
I create a new matrix of the remaining 120*200 elements by using a for loop with 200 iterations, that at round i deletes 40 elements from a copy of the original X according to the indices listed in Tb1(:,i), but it takes too much time and memory.
How can I get the result without using loops and with a minimum number of operations?
Here are different methods:
Method1:
idx = ~hist(tbl, 1:160);
[f,~]=find(idx);
result1 = reshape(M(f),120,200);
Method2:
idx = ~hist(tbl, 1:160);
M2=repmat(M,200,1);
result2 = reshape(M2(idx),120,200);
Method 3 & 4:
% idx can be generated using accumarray
idx = ~accumarray([tbl(:) reshape(repmat(1:200,40,1),[],1)],true,[160,200],#any);
%... use method 1 and 2
Method5:
M5=repmat(M,200,1);
M5(bsxfun(#plus,tbl,0:160:160*199))=[];
result5 = reshape(M5,120,200);
Assuming that M is an array of integers and tbl is the table of indices.
It can be tested with the following data:
M = rand(160,1);
[~,tbl] = sort(rand(160,200));
tbl = tbl(1:40,:);
However it is more efficient if you generate indices of elements to be remained instead of indices of elements to be removed.

Mapping a 2D array into 1D array with variable column width

I know mapping 2D array into 1D array has been asked many times, but I did not find a solution that would fit a where the column count varies.
So I want get a 1-dimensional index from this 2-dimensional array
Col> _0____1____2__
Row 0 |_0__|_1__|_2__|
V 1 |_3__|_4__|
2 |_5__|_6__|_7__|
3 |_8__|_9__|
4 |_10_|_11_|_12_|
5 |_13_|_14_|
The normal formula index = row * columns + column does not work, since after the 2nd row the index is out of place.
What is the correct formula here?
EDIT:
The specific issue is that I have a list of items in with the layout like in the grid, but a one dimensional array for the data. So while looping through the elements in the UI, I need to get the correct data, but can only get the row and column for that element. I need to find a way to turn a row/column value into an index for the data-array
Bad picture trying to explain it
A truly optimal answer (or even a provably correct one) will depend on the language you are using and how it lays out memory for such arrays.
However, taking your question simply at face value, you have to know what the actual length of each row is in order to calculate a 1D index.
So either the row length follows some pattern that can be inferred from the data, or you have (or can write) a rlen = rowLength( 2dTable, RowNumber) function.
Then, depending on how big the tables are and how fast you need to run, you can calculate a 1D index from the 2d table by adding all the previous row lengths until the current row length is less than the 2d column index.
or build a 1d table of the row lengths (or commulative rowlengths) so you can scan it and so only call your rowlength function for each row only once.
With a better description of your problem, you might get a better answer...
For your example which alternates between 3 and 2 columns you can construct a formula:
index = (row / 2) * (3 + 2) + (row % 2 ? 3 : 0) + column
(C-like syntax, assuming integer division)
In general though, the one and only way to implement what you're doing here, jagged arrays, is to make an array of arrays, a.k.a. an Iliffe vector. That means, use the row number as index into an array of pointers which point to the individual row arrays containing the actual data.
You can have an additional 1D array having the length of the columns say "length". Then your formula is index=sum {length(i)}+column. i runs from 0 to row.

cell arrays manipulations in MATLAB --- creating a relation matrix

I have two cell arrays, named as countryname and export.
There is only one column in countryname, which is the code of the names of countries:
USA
CHN
ABW
There are two columns in export:
USA ABW
USA CHN
CHN USA
ABW USA
Each pair (X,Y) in a row of export means "country X has relation with country Y". The size of countryname has been simplified to 3. How can I achieve the following in MATLAB?
Create a square 3 by 3 (in general n by n, where n is the size of countryname) matrix M such that
M(i,j)=1 if country i has relation with country j
M(i,j)=0 otherwise.
The country names are relabeled as positive integers in countryname.
The first thing you need to do is establish a mapping from the country name to an integer value from 1 to 3. You can do that with a containers.Map where the input is a string and the output is an integer. Therefore, we will assign 'USA' to 1, 'CHN' to 2 and 'ABW' to 3. Assuming that you've initialized the cell arrays like you've mentioned above:
countryname = {'USA', 'CHN', 'ABW'};
export = {'USA', 'ABW'; 'USA', 'CHN'; 'CHN', 'USA'; 'ABW', 'USA'};
... you would create a containers.Map like so:
map = containers.Map(countryname, 1:numel(countryname));
Once you have this, you simply map the country names to integers and you can use the values function to help you do this. However, what will be returned is a cell array of individual elements. We need to unpack the cell array, so you can use cell2mat for that. As such, we can now create a 4 x 2 index matrix where each cell element is converted to a numerical value:
ind = cell2mat(values(map, export));
We thus get:
>> ind
ind =
1 3
1 2
2 1
3 1
Now that we have this, you can use sparse to create the final matrix for you where the first column serves as the row locations and the second column serves as the column locations. These locations will tell you where it will be non-zero in your final matrix. However, this will be a sparse matrix and so you'll need to convert the matrix to full to finally get a numerical matrix.
M = full(sparse(ind(:,1), ind(:,2), 1));
We get:
>> M
M =
0 1 1
1 0 0
1 0 0
As a more convenient representation, you can create a table to display the final matrix. Convert the matrix M to a table using array2table and we can add the row and column names to be the country names themselves:
>> T = array2table(M, 'RowNames', countryname, 'VariableNames', countryname)
T =
USA CHN ABW
___ ___ ___
USA 0 1 1
CHN 1 0 0
ABW 1 0 0
Take note that the above code to create the table only works for MATLAB R2013b and above. If that isn't what you require, just stick with the original numerical matrix M.
This is using basic MATLAB functionalities only. Solution posted above by #rayryeng is surely much more advanced and may be faster to code as well. However, this should also help you in understanding at fundamental level
clear
country={'USA','CHN','ABW'};
export={'USA' 'ABW'; 'USA' 'CHN'; 'CHN' 'USA' ; 'ABW' 'USA'};
M=zeros(length(country));
for i=1:length(country)
c=country(i);
ind_state=strfind(export(:,1),char(c)); % this gives state of every which is 1 or blank.
ind_match=find(not(cellfun('isempty', ind_state))); % extracting only indices which are 1.
exp_match=export(ind_match,2); % find corresponding export rel countries from second column
% useful only when your first ind_match matrix has more than 1 element.
% Like 'USA' appears twice in first column of export countries.
for j=1:length(exp_match)
c=exp_match(j);
ind_state=strfind(country,char(c));
ind_match=find(not(cellfun('isempty', ind_state)));
M(i,ind_match)=1; % Selective make elements of M 1 when there is match.
end
end
M

PostgreSQL multidimensional arrays

I'm trying to pass data around as a multidimensional array, and I'm getting behavior that seems odd to me. Specifically I'm trying to get a single element out of a 2 dimensional array (so a 1 dimensional array out of my 2 dimension array), and it doesn't work the way I'd expect.
In the following examples #2, 4, & 5 work the way I'd expect, but 1 & 3 do not.
db=> select s.col[2] from (select array[[1,2,3],[4,5,6]] as col) s;
col
-----
(1 row)
db=> select s.col[2:2] from (select array[[1,2,3],[4,5,6]] as col) s;
col
-----
{{4,5,6}}
(1 row)
db=> select array[s.col[2]] from (select array[[1,2,3],[4,5,6]] as col) s;
array
--------
{NULL}
(1 row)
db=> select array[s.col[2:2]] from (select array[[1,2,3],[4,5,6]] as col) s;
array
-------------
{{{4,5,6}}}
(1 row)
db=> select s.col[2][1] from (select array[[1,2,3],[4,5,6]] as col) s;
col
-----
4
(1 row)
Is there doc on this? I have something that's working well enough for me right now, but it's ugly and I worry it won't do the things I want to do next. Technically I'm getting a 2 dimensional array, where 1 dimension only has 1 element. I'd rather just get an array.
I've read (among others):
http://www.postgresql.org/docs/9.1/static/arrays.html
http://www.postgresql.org/docs/9.1/static/functions-array.html
http://www.postgresql.org/docs/9.1/static/sql-expressions.html#SQL-SYNTAX-ARRAY-CONSTRUCTORS
And I'm just not seeing what I'm looking for.
Postgres array elements are always base elements, i.e. non-array types. Sub-arrays are not "elements" in Postgres. Array slices retain original dimensions.
You can either extract a base element, with element data type. Or you can extract an array slice, which retains the original array data type, and also original array dimensions.
Your idea to retrieve a sub-array as "element" would conflict with that and is just not implemented.
The manual might be made clearer in its explanation. But at least we can find:
If any dimension is written as a slice, i.e., contains a colon, then
all dimensions are treated as slices. Any dimension that has only a
single number (no colon) is treated as being from 1 to the number
specified. For example, [2] is treated as [1:2] ...
Your 1st example tries to reference a base element, which is not found (you'd need a subscript with two array indexes in a 2D array). So Postgres returns NULL.
Your 3rd example just wraps the resulting NULL in a new array.
To flatten an array slice (make it a 1D array) you can unnest() and feed the resulting set to a new ARRAY constructor. Either in a correlated subquery or in a LATERAL join (requires pg 9.3+). Demonstrating both:
SELECT s.col[2:2][2:3] AS slice_arr
, x.lateral_arr
, ARRAY(SELECT unnest(s.col[2:2][2:3])) AS corr_arr
FROM (SELECT ARRAY[[1,2,3],[4,5,6]] AS col) s
, LATERAL (
SELECT ARRAY(SELECT * FROM unnest(s.col[2:2][2:3])) AS lateral_arr
) x;
Be sure to read the current version of the manual. your references point to Postgres 9.1, but chances are you are actually using Postgres 9.4.
Related:
How to select 1d array from 2d array?
Unnest array by one level

Marking and finding locations of elements of array in Matlab

I have a matrix having values between [0,1]. I want to find and mark the locations of those elements which have values <0.1 and >0.9.
So I use the matlab function find; but it returns me two vectors: a row and column vector distinctly which is difficult for analysis. So is there a way by which I can see the location of which elements meet the conditions without losing the original matrix structure?
I used the below line of code:
[r,c,v]= find(X<0.1 | X>0.9); % X is my 512*512 matrix of values
Thanks!
See if this works out for you -
%// cell array with each cell housing the matching indices for each row
out = cellfun(#find,mat2cell(X<0.1 | X>0.9,ones(1,size(X,1)),size(X,2)),'uni',0)
Browse through the values of out using - celldisp(out)
Just by using condition like this :
mask = (X < 0.1 | X > 0.9)
Will return an array logical with 1 where condition is respected.

Resources