I have a list of strings with information about how deep they are located in an XML tree. The strings at "the bottom," i.e. those elements that occur before an element with a lower depth, contain text.
a_text,b_text,c_text,g1_text,b_text,c_text,g2_text,b_text,g1_text,g2_text,b_text,e_text
I would like to reconstitute this as the XML tree below, in one operation.
<AA>
<a>text</a>
<b>text</b>
<c>text</c>
<g1_1>
<g1>text</g1>
<b>text</b>
<c>text</c>
<g2_2>
<g2>text</g2>
<b>text</b>
</g2_2>
</g1_1>
<g1_1>
<g1>text</g1>
<b>text</b>
</g1_1>
<e>text</e></AA>
I don't understand why in your example the penultimate b_text is not in a g2 group, and I don't understand why the final e_text is outside any group. However, the following query:
declare function local:grouping($seq as element()*, $level as xs:integer) as element()* {
for tumbling window $w in $seq
start $s at $p when $p eq 1 or matches(name($s), "^g"||$level)
return if (matches(name($s), "^g"||$level))
then element {name($s)||"_"||$level} {local:grouping($w, $level+1)}
else $w
};
let $seq :=
let $in := "a_text,b_text,c_text,g1_text,b_text,c_text,g2_text,b_text,g1_text,g2_text,b_text,e_text"
for $t in tokenize($in, ",")
return element {substring-before($t, "_")} {substring-after($t, "_")}
return local:grouping($seq, 1)
produces the result
<a>text</a>
<b>text</b>
<c>text</c>
<g1_1>
<g1>text</g1>
<b>text</b>
<c>text</c>
<g2_2>
<g2>text</g2>
<b>text</b>
</g2_2>
</g1_1>
<g1_1>
<g1>text</g1>
<g2_2>
<g2>text</g2>
<b>text</b>
<e>text</e>
</g2_2>
</g1_1>
which is the closest I can get to understanding your requirement.
Related
I've been assigned a task to create a circular linked list in Perl with given arguments, without using arrays or hashes to store the data, only using references. The first element in the structure has a value of 0, irrelevant to the input of the user. It should also support the traversal of the current chosen element using '-' and '+'. The output of the program always starts from the pre-defined element, with the value of 0. So the result should be like this:
./task.pl 3 2 1
0 3 2 1
./task.pl A D - B C + E
0 A B C D E
./task.pl A - B
0 B A
The current code I came up with is :
#!/usr/bin/perl
use strict;
use warnings;
my #elements = #ARGV;
my ($first, $last);
$first = { value => '0', 'prev' => $first, 'next' => $first };
my $pointer = \$first;
for (#elements) {
if ($_ == '-') {
} elsif ($_ == '+') {
} else {
$_ = $pointer->{'next'};
$_ = { value => "$_", 'prev' => $pointer, 'next' => undef};
$pointer = \$_;
$last = $_;
}
}
I am not sure how to proceed further with this, also no imports like Class::Struct can be used.
First of all, you are using a hash. {} creates a hash and returns a reference to it. THIS IS CORRECT. The hash is being used as a struct/class, which isn't what the assignment wants you to avoid.
Secondly, you have $first and $last and a bogus initial element. All of that is wrong. You just need my my $pointer;, although I would call it my $current;.
Thirdly, you use references to scalars (\$var). This is not useful here. The references to the hashes returned by {} are sufficient.
On to the code. There are three different components: Inserting the first element, + and -, insertions, and printing the list that was built.
Inserting the first element
The first argument is special. It can't be + and -. Other insertions always insert after another element, but that's not the case for the first insertion.
In short, we create a list that consists entirely of a node whose value is the first element.
We used undef to indicate a non-existent node.
my $pointer = { value => shift(#elements), prev => undef, next => undef };
+ and -
+ and - change the current node (as indicated by $pointer).
If + is received, you want $pointer to the point to the node to which the current node's prev field points.
If - is received, you want $pointer to the point to the node to which the current node's prev field points.
You always have to ask yourself if there's a special cases, and there is one for each of + and -. There could be an attempt to reach a node before the first (A - -), and there could be an attempt to reach a node after the last (A +). You should die if an attempt is made to reach a non-existent node.
Insertions
We always insert after the current node (the one $pointer references).
Again we ask ourselvves if there's a special case (like trying to use - when already at the first node). But there are none. $pointer will always point to a valid node.
After inserting a node in the list, we want to make $pointer reference the newly created/inserted node.
Printing the list
We want to print the entire list from start to end, so we will need to start by finding the start of the list. This is the same operation as - applied repeatedly until the first node is found. (The first node is the one which has no previous node.)
Then, it's just a question of traversing the list in the other direction (like + does), printing the values as you go along.
<record>
<node_1>
<value_1_0>5</value_1_0>
<value_1_1>0</value_1_1>
<value_1_2>10</value_1_2>
<value_1_3>8</value_1_3>
</node_1>
.................................
.................................
<node_63>
<value_63_0>1</value_63_0>
<value_63_1>99</value_63_1>
<value_63_2>53</value_63_2>
<value_63_3>5</value_63_3>
</node_63>
</record>
Problem statement :
How to write efficient XPath expressions for these two cases?
if value is non zero for any node, I need to check if value of that particular subnode for previous and next node are non zero. i.e. if node_50/value_50_0 is non zero, node49/value_49_0 and node51/value_51_0 should also be non zero. Similarly, for rest of the cases.
Next, it should add up the values for alternate nodes. i.e. node_1/value_1_0 + node_3/value_1_0 + ... + node_63/value_1_0. Similarly, for value_1_1,...,value_63_1 and so on.
I am wondering if there is any "for loop" with counter variable provision for each index, so that the XPath expression will be simple for both cases?
pseudo code :
for(i=1; i<64; i++)
for(j=0;j<4;j++)
if (node_i/value_i_j !=0)&& (node_i-1/value_i-1_j !=00)&&(node_i-1/value_i-1_j!=0)
True
else
False
end
end
Using
let $alternate-nodes := /record/*[position() mod 2 = 1]
for $i in (1 to count($alternate-nodes[1]/*))
return
sum($alternate-nodes/*[position() eq $i])
should do to compute the sums. Of course the use of for $i in is only necessary if the element names are really as complicated as in the input where each has one or two index numbers in the name.
For the test for zero or non-zero values should be possible with e.g.
let $nodes := /record/*
for $i in (1 to count($nodes[1]/*))
return every $value in $nodes/*[position() eq $i] satisfies $value != 0
to return a sequence of boolean values.
Explaining with words when 2 hashes would match is complicated, so, see the example:
Hash patterns are stored in a list like: (I'm using JavaScript for notation)
pattern:[
0:{type:'circle', radius:function(n){ return n>10; }},
1:{type:'circle', radius:function(n){ return n==2; }},
2:{type:'circle', color:'blue', radius:5},
... etc]
var test = {type:'circle', radius:12};
test should match with pattern 0 because pattern[0].type==test.type && pattern.radius(test.radius)==true.
So, trying with words, a hash matches a pattern if every of it's values is either equal of those of the pattern or returns true when applied as a function.
My question is: is there an algorithm to find all patterns that match certain hash without testing all of them?
Consider a dynamic, recursive, decision tree structure like the following.
decision:[
field:'type',
values:[
'circle': <another decision structure>,
'square': 0, // meaning it matched, return this value
'triangle': <another decision structure>
],
functions:[
function(n){ return n<12;}: <another decision structure>,
function(n){ return n>12;}: <another decision structure>
],
missing: <another decision structure>
]
Algorithm on d (a decision structure):
if test has field d.field
if test[d.field] in d.values
if d.values[test[d.field]] is a decision structure
recurse using the new decision structure
else
yield d.values[test[d.field]]
foreach f => v in d.functions
if f(test[d.field])
if v is a decision structure
recurse using the new decision structure
else
yield v
else if d.missing is present
if d.missing is a decision structure
recurse using the new decision structure
else
yield d.missing
else
No match
I have a Cshell script that I am modifying to have related input and output locations.
the functionality all happens in a foreach loop like so:
set INPUT_LOCATION_LIST = "loc1 loc2 loc3 loc4"
foreach location ($INPUT_LOCATION_LIST)
#***Do some stuff ***
end
I would like to have an output list with different values than the input list but traverse through it each iteration through the foreach loop. The man for foreach simply has
foreach name (wordlist)
as the definition. so only dealing with a single one. my current thought on dealing with it is have the wordlist contain both input and output location and then parse it out in the script:
set INPUT_LOCATION_LIST = "loc1;out1 loc2;out2 loc3;out3 loc4;out4"
so im wondering if anyone has a better way to do that.
You can iterate through one list using foreach and through the other one by treating at like an array and using shift:
set INPUT_LOCATION_LIST = "loc1 loc2 loc3 loc4"
set OUT_LIST = (out1 out2 out3 out4)
foreach location ($INPUT_LOCATION_LIST)
do_something $location $OUT_LIST[1]
shift OUT_LIST
end
I don't normally use csh, but your question caught my eye. There's probably a solution with less steps, but this kind of thing worked in my version of csh:
foreach location ($INPUT_LOCATION_LIST)
set one_word_with_space = ${location:s/;/ /}
set loc_out = ($one_word_with_space)
set loc = ${loc_out[1]}
set out = ${loc_out[2]}
...
end
Basic idea is just to change the semi-colon separated string into a space-separated string, then parse that into an array.
What type of algorithm would be used to construct a syntax tree from an expression represented in prefix order notation?
A simple recursive algorithm can convert a prefix-order expression to a syntax tree.
GetNextPrefixExpression(tokenStream)
nextToken = tokenStream.GetNextToken()
if nextToken.IsValue()
return new Value(nextToken)
else if nextToken.IsUnaryOperator()
return new UnaryOperator(nextToken, GetNextPrefixExpression(tokenStream))
else if nextToken.IsBinaryOperator()
return new BinaryOperator(nextToken, GetNextPrefixExpression(tokenStream), GetNextPrefixExpression(tokenStream))
else if nextToken.IsTrinaryOperator()
return new TrinaryOperator(nextToken, GetNextPrefixExpression(tokenStream), GetNextPrefixExpression(tokenStream), GetNextPrefixExpression(tokenStream))