I have two lists, which are both list of lists of the same lengths
list1 [[1 3 5 7] [2 5 1 6]]
list2 [[0.5 0.3 0.7 0.1] [0.1 0.4 0.6 0.2]]
My task is: if a number in list2 is <= e.g 0.2, remove items at corresponding position from list1. So based on the above example items in list2 which are <= 0.2 are [[3] [0 3]] and the final list1 should look like this [[1 3 5] [5 1]]. The same items should then be removed from list2 so its final version would look like [[0.5 0.3 0.7] [0.4 0.6]].
The below code works well but becomes very slow if the list is long (which is the case in my model)
Is the any efficient way of doing it without running loop of a loop?
let k 0
foreach list2
[
x ->
let each_element_list2 x
let each_element_list1 k list1
(foreach each_element_list2
[
i ->
if i <= 0.2
[
let rem_pos position i each_element_list2
set each_element_list2 remove-item rem_pos each_element_list2
set each_element_list1 remove-item rem_pos each_element_list1
]
]
)
set list2 replace-item k list2 each_element_list2
set list1 replace-item k list1 each_element_list1
set k k + 1
]
Thanx in advance,
Magda
This is not the most elegant code, and I don't have time to explain it step by step, but something like this should work:
to remove-items
let list1 [[1 3 5 7 ] [2 5 1 6 ]]
let list2 [[0.5 0.3 0.7 0.1] [0.1 0.4 0.6 0.2]]
if length list1 != length list2 [ error "lists should be of equal length" ]
foreach range length list1 [ i ->
let sl1 item i list1 ; extract sublist 1
let sl2 item i list2 ; extract sublist 2
let indices-to-keep (
map first ; extract the index from the pair
filter [ p -> last p > 0.2 ] ; keep the pairs where the item is <= 0.2
(map list range (length sl2) sl2) ; build a list of index/item pairs
)
let replace-sublist [ [l sl] ->
replace-item i l (map [ j -> item j sl ] indices-to-keep)
]
set list1 (runresult replace-sublist list1 sl1)
set list2 (runresult replace-sublist list2 sl2)
]
print list1
print list2
end
Just one quick note: notice that I inverted the condition (i.e., > 0.2 instead of <= 0.2), as it's easier to use a list of the indices we want to keep instead of those we want to remove.
Related
Why won't the following run?
if (map [ [a b c] -> a + b = c ] [1] [2] [3]) [show 100]
The following produces 'true' as an output:
show (map [ [a b c] -> a + b = c ] [1] [2] [3])
so I expected the first statement above to be the same as:
if true [show 100]
(P.S. in my full version the lists are longer but are collapsed into a single true/false using reduce.)
Thanks.
To elaborate on ThomasC's comment, map always produces a list, even if it only has one element. So
(map [ [a b c] -> a + b = c ] [1] [2] [3])
does produce [true]. Thus
(map [ [a b c] -> a + b = c ] [1 2] [2 3] [3 5])
will produce [true true]. reduce is helpful here,
reduce AND (map [ [a b c] -> a + b = c ] [1 2] [2 3] [3 5])
will produce a simple true by "anding" all the elements of the map output, and
reduce AND (map [ [a b c] -> a + b = c ] [1 2] [2 3] [3 6])
will produce a simple false.
I'm trying to create a program which solves linear systems using Gaussian Elimination. The program should consist of two parts. The forwards phase and a phase for Back-substitution.
Right now I am working on the forward phase. However, I can't figure out a method for treating the diagonal elements.
I've tried implementing if-statments which should do the row-operation for the element below the element on the diagonal.
function A = mygausselm(A)
[m,n] = size(A);
for k=1:n-1 %columns
for i=1:m-1 %rows
L = A(i+1,k)/A(k,k);
A(i+1,:)= A(i+1,:)- L*A(k,:);
end
end
end
Take the matrix:
[ 1 2 3 ]
A= [ 4 3 2 ]
[ 7 5 4 ]
The expected output should then be after the row-operations
[ * * * ]
A= [ 0 * * ]
[ 0 0 * ]
Your i index was starting wrong. Don't start from line 1, start from the next line under the diagonal element k you work on:
for k=1:n-1 %columns
for i=k+1:m %rows
L = A(i,k)/A(k,k);
A(i,:)= A(i,:)- L*A(k,:);
end
end
Since you know that when working on column k, all rows under row k have their first (k-1) elements zero, you can avoid operations on them:
for k=1:n-1 %columns
for i=k+1:m %rows
L = A(i,k)/A(k,k);
A(i,k:end)= A(i,k:end)- L*A(k,k:end);
end
end
I want to take an arbitrary 1D vector a = [k] and b = [m] and form the matrix of ordered pairs c = [2 x k x m] such that $c->(:,(i),(j)) = [ $a->(i), $b->(j) ]. I.e. the set of all ordered pairs of the elements in a and b a.k.a the cartesian product.
Of course I could use a loop and the [glue] function to accomplish this, but that isn't in the spirit of Perl/PDL. Is there a fancy method that involves slices, dummy dimensions, and glue that gets me there?
Also, using Math::Cartesian::Product (as answered here: In Perl, how can I get the Cartesian product of multiple sets? is cheating! :3 I want straight perl/PDL and hopefully learn something in the process.
I got something that meets my criteria:
my $a = pdl 1,2,3,4;
my $b = pdl 5,6,7;
print "a = $a\n";
print "b = $b\n";
print "dummy dimensioned:\n";
$a = $a->dummy(0,$b->dim(0));
print "a".$a->shape." = $a\n";
$b = $b->dummy(0, $a->dim(1))->transpose;
print "b".$b->shape." = $b\n";
print "Glued together:\n"
my $c = $a->dummy(0,1)->glue(0, $b->dummy(0,1));
print "c".$c->shape." = $c\n";
a = [1 2 3 4]
b = [5 6 7]
dummy dimensioned:
a[3 4] =
[
[1 1 1]
[2 2 2]
[3 3 3]
[4 4 4]
]
b[3 4] =
[
[5 6 7]
[5 6 7]
[5 6 7]
[5 6 7]
]
Glued together:
c[2 3 4] = [[[1 5][1 6][1 7]][[2 5][2 6][2 7]][[3 5][3 6][3 7]][[4 5][4 6][4 7]]]
I have a structure with fields ID,Coor,Misc,Conn. ID and Misc are doubles, however, Coor is a 1x3 vector and Conn is a 1xn vector (where n can theoretically be from 0 to inf).
Point(x).ID = [x]
Point(x).Coordinate = [xPos yPos zPos]
Point(x).Misc = [randomDouble]
Point(x).Conn = [someVectorOfNumbers]
I would like to have this mapped on a cell array, without using a FOR loop.
An example of the output:
'ID xPos yPos zPos Misc Conn'
1 0 0 0 0 '0 1 2'
2 1 1 1 1 ''
...
x x x x x '2'
Notice that Point.Conn, its vector of numbers gets converted into a string.
The issues that I am having is breaking up Point.Coordinate into its three elements, and converting Point.Conn into a string.
I feel like this can be done using struct2Cell and then changing the nesting level. I'm just not exactly sure how to do that.
First make some example data:
n = 10;
ID = num2cell(randperm(n)');
Coordinate = mat2cell(randn(n, 3), ones(n,1));
Misc = num2cell(randn(n,1));
Conn = arrayfun(#randperm, randperm(n), 'UniformOutput', 0)';
Point = struct('ID', ID, 'Coordinate', Coordinate, 'Misc', Misc, 'Conn', Conn);
Now inspect it:
>> Point
Point =
10x1 struct array with fields:
ID
Coordinate
Misc
Conn
>> Point(1)
ans =
ID: 7
Coordinate: [-0.0571 -1.1645 2.4124]
Misc: 0.0524
Conn: [3 2 1]
Now use arrayfun() to sweep through the elements of structure array Point. We define a generic function x to operate on each element of Point, formatting the row like you described:
Point_cell = arrayfun(#(x) [num2cell([x.ID x.Coordinate x.Misc]) num2str(x.Conn)], Point, 'UniformOutput', 0);
Point_cell = vertcat(Point_cell{:})
Now inspect the output:
ans =
[ 7] [-0.0571] [-1.1645] [ 2.4124] [ 0.0524] '3 2 1'
[ 5] [ 0.2918] [ 0.4948] [ 0.7402] [-1.9539] '1 2'
[ 3] [-0.6146] [-1.2158] [ 0.3097] [ 0.5654] '3 4 1 2'
[10] [-0.0136] [ 1.5908] [-0.5420] [ 0.0778] [1x25 char]
[ 2] [ 0.4121] [ 0.5265] [ 0.1223] [ 0.0807] [1x22 char]
[ 1] [-0.9371] [ 0.2648] [ 0.9623] [ 0.7947] '1 2 5 4 3'
[ 4] [ 0.8352] [-0.3936] [-0.2540] [ 1.0437] '6 2 3 7 4 1 5'
[ 8] [ 1.0945] [-2.1763] [ 1.8918] [ 0.8022] '1'
[ 6] [ 0.3212] [-1.1957] [-1.2203] [-0.4688] [1x37 char]
[ 9] [ 0.0151] [ 0.3653] [-0.3762] [-0.0466] '3 5 4 2 6 1'
Couldn't tell from your question, but if you want all the numeric fields as an array inside a single cell, that is an easy tweak to do. Good luck!
Here is a slightly different solution using STRUCT2CELL:
%# build a sample array of structures
id = num2cell((1:10)',2); %'
coords = num2cell(rand(10,3),2);
misc = num2cell(rand(10,1),2);
conn = arrayfun(#(n)randi(5,[1 n]), randi([0 6],[10 1]), 'UniformOutput',false);
p = struct('ID',id, 'Coordinate',coords, 'Misc',misc, 'Conn',conn);
%# convert to cell array
h = fieldnames(p)'; %'
X = struct2cell(p)'; %'
%# split 'coords' field into 3 separate columns
h2 = {'xPos' 'yPos' 'zPos'};
X2 = num2cell( cell2mat(X(:,2)) );
%# convert 'conn' field to string
X4 = cellfun(#num2str, X(:,4), 'UniformOutput',false);
X4 = regexprep(X4, '[ ]+', ' '); %# clean multiple spaces as one
%# build final cell array with headers
C = [h(1) h2 h(3:4) ; X(:,1) X2 X(:,3) X4]
The result:
>> C
C =
'ID' 'xPos' 'yPos' 'zPos' 'Misc' 'Conn'
[ 1] [0.78556] [ 0.46707] [0.66281] [ 0.46484] '3'
[ 2] [0.51338] [ 0.6482] [0.33083] [ 0.76396] '2 1 2 5 1 2'
[ 3] [ 0.1776] [0.025228] [0.89849] [ 0.8182] '1 3 1 5'
[ 4] [0.39859] [ 0.84221] [0.11816] [ 0.10022] '1 1 2'
[ 5] [0.13393] [ 0.55903] [0.98842] [ 0.17812] '3 1 5 2 2 1'
[ 6] [0.03089] [ 0.8541] [0.53998] [ 0.35963] ''
[ 7] [0.93914] [ 0.34788] [0.70692] [0.056705] '2 1 3 4 4'
[ 8] [0.30131] [ 0.44603] [0.99949] [ 0.52189] '1 1 4 5 3'
[ 9] [0.29553] [0.054239] [0.28785] [ 0.33585] '1 5 2'
[10] [0.33294] [ 0.17711] [0.41452] [ 0.17567] '2'
where for example the second structure was:
>> p(2)
ans =
ID: 2
Coordinate: [0.51338 0.6482 0.33083]
Misc: 0.76396
Conn: [2 1 2 5 1 2]
What does this instruction vector=[vector,sum(othervector)] does in matlab inside a while loop like:
vector=[];
while a - b ~= 0
othervector = sum(something') %returns a vector
vector=[vector,sum(othervector)]; %it keeps a new vector?
...
end
vector=vector./100
Executing a = [a,b] means append b to a, thus vector will eventually be a matrix where each column is the row-wise sum of something'.
More concretely: suppose something' is this matrix:
something' = [ 1, 2; 3, 4 ];
Then sum(something') is:
othervector = [ 3 ; 7 ]
And initially vector is empty, so this sets vector to
vector = [ 3 ; 7 ]
Suppose we repeat with a new something' consisting of
[ 5, 5; 5, 6 ]
Then sum(something') is:
othervector = [ 10; 11 ]
And now we augment this to vector using vector = [vector, sum(othervector)]:
vector = [ vector, [10; 11] ] = [ 3, 10 ; 7, 11 ]