Given a table and a function
t:([] c1:1 2 3; c2:`a`b`c; c3:13:00 13:01 13:02)
f:{[int;sym;date]
symf:{$[x=`a;1;x=`b;2;3]};
datef:{$[x=13:00;1;x=13:01;2;3]};
r:int + symf[sym] + datef[date];
r
};
I noticed that when applying the function f onto columns of t, then the entire columns are passed into f and if they can be operated on atomically then the output will be of the same length as the inputs and a new column is produced. However in our example this wont work:
update newcol:f[c1;c2;c3] from t / 'type error
because the inner functions symf and datef cannot be applied to the entire column c2, c3, respectively.
If I dont want to change the function f at all, how can I apply it row by row and collect the values into a new column in t.
What's the most q style way to do this?
EDIT
If not changing f is really inconvenient one could workaround like so
f:{[arglist]
int:arglist 0;
sym:arglist 1;
date:arglist 2;
symf:{$[x=`a;1;x=`b;2;3]};
datef:{$[x=13:00;1;x=13:01;2;3]};
r:int + symf[sym] + datef[date];
r
};
f each (t`c1),'(t`c2),'(t`c3)
Still I would be interested how to get the same result when working with the original version of f
Thanks!
You can use each-both for this e.g.
q)update newcol:f'[c1;c2;c3] from t
c1 c2 c3 newcol
------------------
1 a 13:00 3
2 b 13:01 6
3 c 13:02 9
However you will likely get better performance by modifying f to be "vectorised" e.g.
q)f2
{[int;sym;date]
symf:3^(`a`b!1 2)sym;
datef:3^(13:00 13:01!1 2)date;
r:int + symf + datef;
r
}
q)update newcol:f2[c1;c2;c3] from t
c1 c2 c3 newcol
------------------
1 a 13:00 3
2 b 13:01 6
3 c 13:02 9
q)\ts:1000 update newcol:f2[c1;c2;c3] from t
4 1664
q)\ts:1000 update newcol:f'[c1;c2;c3] from t
8 1680
In general in KDB, if you can avoid using any form of each and stick to vector operations, you'll get much more efficiency
I have a question about removing duplicates in a table (rexx language), I am on netphantom applications that are using the rexx language.
I need a sample on how to remove the duplicates in a table.
I do have a thoughts on how to do it though, like using two loops for these two tables which are A and B, but I am not familiar with this.
My situation is:
rc = PanlistInsertData('A',0,SAMPLE)
TABLE A (this table having duplicate data)
123
1
1234
12
123
1234
I need to filter out those duplicates data into TABLE B like this:
123
1234
1
12
You can use lookup stem variables to test if you have already found a value.
This should work (note I have not tested so there could be syntax errors)
no=0;
yes=1
lookup. = no /* initialize the stem to no, not strictly needed */
j=0
do i = 1 to in.0
v = in.i
if lookup.v <> yes then do
j = j + 1
out.j = v
lookup.v = yes
end
end
out.0 = j
You can eliminate the duplicates by :
If InStem first element, Move the element to OutStem Else check all the OutStem elements for the current InStem element
If element is found, Iterate to the next InStem element Else add InStem element to OutStem
Code Snippet :
/*Input Stem - InStem.
Output Stem - OutStem.
Array Counters - I, J, K */
J = 1
DO I = 1 TO InStem.0
IF I = 1 THEN
OutStem.I = InStem.I
ELSE
DO K = 1 TO J
IF (InStem.I ?= OutStem.K) & (K = J) THEN
DO
J = J + 1
OutStem.J = InStem.I
END
ELSE
DO
IF (InStem.I == OutStem.K) THEN
ITERATE I
END
END
END
OutStem.0 = J
Hope this helps.
I have a set of collinear line segments (may be mutually disjoint, contained, or overlapping).
I want to make a new set of line segments where the segments are disjoint or touching (not overlapping), and each line segment has a count of the original line segments that cover it.
For example, suppose the original set is (drawn non-collinearly for illustration):
A----------------------B
C---------------------------D
E-----F
G-------------H
I-------J
the desired new set would be:
A-------C---E-----F-----B-----------D G-------------H-------J
1 2 3 2 1 1 1
(only the point coordinates matter, the new set does not share point objects with the old set)
How can I achieve this with PostGIS?
Related question: suppose I start with a table of line segments, not all collinear, how do I write the entire query that groups the collinear segments together and then applies the solution to my first question?
Thanks for any help!
Setup (for later queries):
create table lines (
id serial primary key,
label text not null,
line_data geometry(linestring) not null
);
insert into lines(label, line_data)
values ('A-B', ST_MakeLine(ST_MakePoint(-3, -6), ST_MakePoint( 1, 2))),
('D-C', ST_MakeLine(ST_MakePoint( 2, 4), ST_MakePoint(-2, -4))),
('E-F', ST_MakeLine(ST_MakePoint(-1, -2), ST_MakePoint( 0, 0))),
('G-H', ST_MakeLine(ST_MakePoint( 3, 6), ST_MakePoint( 4, 8))),
('I-J', ST_MakeLine(ST_MakePoint( 4, 8), ST_MakePoint( 5, 10))),
('P-L', ST_MakeLine(ST_MakePoint( 1, 0), ST_MakePoint( 2, 2))),
('X-Y', ST_MakeLine(ST_MakePoint( 2, 2), ST_MakePoint( 0, 4)));
Notes:
I purposely switched your D and C points to demonstrate a need for vector negation
The P-L line is parallel with your example lines (but not collinear)
The X-Y line has nothing to do with the others
the solutions below obviously won't work, when you have linestrings that have more than 2 points and those are not on the same line (so when a single linestring is not straight).
The ST_Union aggregate function can split your collinear linestrings. You'll just need to calculate how many lines are containing those.
However, grouping by collinearity is not that simple. I did not find any out-of-the-box solution for this, but you can calculate it (this will not calculate counts yet):
select string_agg(label, ','), ST_AsText(ST_Multi(ST_Union(line_data)))
from lines
group by (
select case
when ST_SRID(s) <> ST_SRID(e) then row(ST_SRID(s), s, null)
when ST_X(s) = ST_X(e) then row(ST_SRID(s), ST_SetSRID(ST_MakePoint(ST_X(s), 1.0), ST_SRID(s)), null)
when ST_Y(s) = ST_Y(e) then row(ST_SRID(s), ST_SetSRID(ST_MakePoint(1.0, ST_Y(e)), ST_SRID(s)), null)
else (
select row(
ST_SRID(s),
(select case
when ST_Y(rv) < 0
then ST_SetSRID(ST_MakePoint(-ST_X(rv), -ST_Y(rv)), ST_SRID(s))
else rv
end), -- normalized vector (negated when necessary, but same for all parallel lines)
(ST_X(e) * ST_Y(s) - ST_X(s) * ST_Y(e)) / (ST_X(e) - ST_X(s)) -- solution of the linear equaltion, where x=0
)
from coalesce(1.0 / nullif(ST_Distance(s, e), 0), 0) dmi, -- distance's multiplicative inverse
ST_TransScale(e, -ST_X(s), -ST_Y(s), dmi, dmi) rv -- raw vector (translated and scaled)
)
end
from ST_StartPoint(line_data) s,
ST_EndPoint(line_data) e
)
will produce:
X-Y | MULTILINESTRING((2 2,0 4))
P-L | MULTILINESTRING((1 0,2 2))
E-F,A-B,I-J,G-H,D-C | MULTILINESTRING((-3 -6,-2 -4),(-2 -4,-1 -2),(-1 -2,0 0),(0 0,1 2),(2 4,1 2),(3 6,4 8),(4 8,5 10))
To calculate counts, JOIN your original data again, where the splitted lines are contained by (ST_Contains) your original lines:
select ST_AsText(splitted_line), count(line_data)
from (select ST_Multi(ST_Union(line_data)) ml
from lines
group by (
select case
when ST_SRID(s) <> ST_SRID(e) then row(ST_SRID(s), s, null)
when ST_X(s) = ST_X(e) then row(ST_SRID(s), ST_SetSRID(ST_MakePoint(ST_X(s), 1.0), ST_SRID(s)), null)
when ST_Y(s) = ST_Y(e) then row(ST_SRID(s), ST_SetSRID(ST_MakePoint(1.0, ST_Y(e)), ST_SRID(s)), null)
else (
select row(
ST_SRID(s),
(select case
when ST_Y(rv) < 0
then ST_SetSRID(ST_MakePoint(-ST_X(rv), -ST_Y(rv)), ST_SRID(s))
else rv
end), -- normalized vector (negated when necessary, but same for all parallel lines)
(ST_X(e) * ST_Y(s) - ST_X(s) * ST_Y(e)) / (ST_X(e) - ST_X(s)) -- solution of the linear equaltion, where x=0
)
from coalesce(1.0 / nullif(ST_Distance(s, e), 0), 0) dmi, -- distance's multiplicative inverse
ST_TransScale(e, -ST_X(s), -ST_Y(s), dmi, dmi) rv -- raw vector (translated and scaled)
)
end
from ST_StartPoint(line_data) s,
ST_EndPoint(line_data) e)) al,
generate_series(1, ST_NumGeometries(ml)) i,
ST_GeometryN(ml, i) splitted_line
left join lines on ST_Contains(line_data, splitted_line)
group by splitted_line
will return:
LINESTRING(-3 -6,-2 -4) | 1
LINESTRING(-2 -4,-1 -2) | 2
LINESTRING(-1 -2,0 0) | 3
LINESTRING(0 0,1 2) | 2
LINESTRING(2 2,0 4) | 1
LINESTRING(1 0,2 2) | 1
LINESTRING(2 4,1 2) | 1
LINESTRING(3 6,4 8) | 1
LINESTRING(4 8,5 10) | 1
I need to traverse all vertices that are connected by edges where the property 'dependence' is 'true'
This is what I have so far:
SELECT
FROM (TRAVERSE *
FROM (SELECT outE() FROM 9:5)
WHILE (#class = 'E' AND dependence = 'yes') OR #class = 'V')
WHERE #class = 'V'
Although im not sure if is the best way to do it, this seems to work fine following only the paths where edges have 'dependence' = 'yes'.
Now, There could be more than one path generated, and I need to get the last vertex from each path/branch.
traverserdVertex(-1) should return the last one, but im guessing that is from the whole traversal so is no good. (and it looks like there's a bug because it retrieves more than one)
The outer SELECT returns the whole bag of vertices so I'm thinking that maybe finding the ones that doesn't have an outgoing edge with dependence='yes' might solve it, although I'm not sure how to do it nicely.
SOLUTION:
SELECT
FROM (TRAVERSE *
FROM (SELECT outE() FROM 9:5)
WHILE (#class = 'E' AND dependence = 'yes') OR #class = 'V')
WHERE #class = 'V' AND NOT (outE() contains (dependence='yes'))
This effectively returns the last vertex from each branch. I'm open to any other option, I'm wondering if it could be improved.
I tried with an example by building the following graph
The javascript function "myFunction" has three parameters which are ridVertex, property and value
var g=orient.getGraph();
var previous=[];
var currently=[];
var node=[];
var b=g.command("sql","select from v where #rid =" + ridVertex);
if(b.length>0){
previous.push(b[0]);
node.push(b[0]);
do{
for(i=0;i<previous.length;i++){
var edges=g.command("sql","select expand(outE()) from V where #rid = "+ previous[i].getId());
var myVertex=[];
for(j=0;j<edges.length;j++){
var edge=edges[j];
var dependence=edge.getProperty(property);
if(dependence==value){
var vIn=edge.getProperty("in");
myVertex.push(vIn);
}
}
if(myVertex.length>0){
setPaths();
}
}
change();
}while(previous.length>0);
}
return node;
function setPaths(){
for (m = 0; m < node.length; m++) {
var lastId=node[m].getId().toString();
var idOut=previous[i].getId().toString();
if (lastId==idOut) {
for(r=0;r<myVertex.length;r++){
var vertex=myVertex[r];
node.push(vertex);
currently.push(vertex);
}
node.splice(m,1);
break;
}
}
}
function change(){
previous=[];
for (indice=0;indice<currently.length;indice++)
previous.push(currently[indice]);
currently=[];
}
Using the following command
select expand(result) from (select myFunction("#9:0","dependence","yes") as result)
the paths are A -> D and A -> B -> C -> G and then will be returned the verteces D and G
The following is a slight simplification of #sebastian's solution, using Allesandro's graph (with dependentOn.value being 0 or 1):
select from
(TRAVERSE * FROM (select from Circle where name="A")
while (#CLASS="dependentOn" and value=1) OR #CLASS="Circle")
where #CLASS='Circle' AND NOT (outE().value contains 1)
----+-----+------+----+--------------
# |#RID |#CLASS|name|in_dependentOn
----+-----+------+----+--------------
0 |#11:6|Circle|G |[#12:4]
1 |#11:3|Circle|D |[#12:1]
I have 100 nodes using following for loop:
xm1=100; %diameters of sensor network
ym1=100;
sink1.x=50; %distance of base station from the network
sink1.y=120;
nl = 100; %no of nodes
pl=0.1; %probibilty of a node to become cluster head
El1= 0;
Eint=0.5; %energy supplied to each node
Etl =0 ;
for i=1:1:nl
Sl(i).xd=rand(1,1)*xm1; %it will distribute the nodes in 1 dimension in x axis randomly.
XR(i)=Sl(i).xd; %we store its value in xr
Sl(i).yd=rand(1,1)*ym1; %it will distribute the nodes in 1 dimension in y axis randomly
YR(i)=Sl(i).yd;
Sl(i).id = i;
Sl(i).G=0; % as the no of node that have been cluster head is zero 0
Sl(i).E=Eint; %%*(1+rand*a);
%fprintf(' Sensor node energy: %15f \n',Eint); %?
%initially there are no cluster heads only nodes
Sl(i).type='N';
end
cluster formation took place like tis
for r=1:1:rmax
for i=1:1:nl
if(Sl(i).E>0)
temp_randl=rand;
if ( (Sl(i).G)<=0)
if(temp_randl<= (pl/(1-pl*mod(r,round(1/pl)))))
countCHsl=countCHsl+1;
packets_TO_BSl=packets_TO_BSl+1;
PACKETS_TO_BSl(r+1)=packets_TO_BSl;
Sl(i).type='C';
Sl(i).G=round(1/pl)-1;
Cl(clusterl).xd=Sl(i).xd;
Cl(clusterl).yd=Sl(i).yd;
distancel=sqrt( (Sl(i).xd-(Sl(n+1).xd) )^2 + (Sl(i).yd-(Sl(n+1).yd) )^2 );
Cl(clusterl).distance=distancel;
Cl(clusterl).id=i;
X(clusterl)=Sl(i).xd;
Y(clusterl)=Sl(i).yd;
clusterl=clusterl+1;
distancel;
if (distancel>do)
Sl(i).E=Sl(i).E- ( (ETX+EDA)*(4000) + Emp*4000*(distancel*distancel*distancel*distancel ));
end
if (distancel<=do)
Sl(i).E=Sl(i).E- ( (ETX+EDA)*(4000) + Efs*4000*(distancel * distancel ));
end
end
end
% S(i).G=S(i).G-1;
end
end
STATISTICS.COUNTCHS(r+1)=countCHsl;
for i=1:1:nl
if ( Sl(i).type=='N' && Sl(i).E>0 )
if(clusterl-1>=1)
min_disl=Inf;
min_dis_clusterl=0;
for cl=1:1:clusterl-1
templ=min(min_disl,sqrt( (Sl(i).xd-Cl(cl).xd)^2 + (Sl(i).yd-Cl(cl).yd)^2 ) );
if ( templ<min_disl )
min_disl=templ;
min_dis_clusterl=cl;
end
end
min_disl;
if (min_disl>do)
Sl(i).E=Sl(i).E- ( ETX*(4000) + Emp*4000*( min_disl *min_disl * min_disl * min_disl));
end
if (min_disl<=do)
Sl(i).E=Sl(i).E- ( ETX*(4000) + Efs*4000*( min_disl * min_disl));
end
Sl(Cl(min_dis_clusterl).id).E =Sl(Cl(min_dis_clusterl).id).E- ( (ERX + EDA)*4000 );
packets_TO_CHl=packets_TO_CHl+1;
Sl(i).min_disl=min_disl;
Sl(i).min_dis_clusterl=min_dis_clusterl;
else
min_disl=sqrt( (Sl(i).xd-Sl(n+1).xd)^2 + (Sl(i).yd-Sl(n+1).yd)^2 );
if (min_disl>do)
Sl(i).E=Sl(i).E- ( ETX*(4000) + Emp*4000*( min_dis1 *min_dis1 * min_dis1 * min_dis1));
end
if (min_disl<=do)
Sl(i).E=Sl(i).E- ( ETX*(4000) + Efs*4000*( min_disl * min_disl));
end
packets_TO_BSl=packets_TO_BSl+1;
end
end
end
end
Now I have to print value of S1(i).E for all i after every round?
Means I have to print remaining energy of all nodes at every round.
Thanks in advance.
And the exact answer of this question is
fprintf('%0.2f \n',Sl(:).E);
I assume r stands for round, so you could add any of the following lines right before your last end to print the remaining energy:
sprintf('%0.2f \n',Sl(:).E);
disp([Sl(:).E]');
Sl(:).E
a simple
S1(i).E,
should work.