XPath expression to compute arithmetics on array of nodes - xpath

<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.

Related

How to create a circular linked list in Perl without using arrays?

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.

how to use while loop in pseudocode

I am trying to add the user inputs using a while loop and If statements. I am having trouble figuring out how to add all the userNumbers to each other. Any help would be appreciated.
//variables
Declare Integer userIn = 0
Declare Integer total = 0
//read numbers and calculate
While decision == decY
Display “Please enter your numbers: ”
Input decision
If UserIn > 0
Display userNumbers
Set total = userIn + 1
Display “Would you like to enter another number Y/N?”
Input decision
If decision == decN
Display “Done reading numbers, your total is ”, total
End If
End If
End While
Decide on a separator for the input, unless they're only allowed to enter a single number at a time in which case you can skip to 3.
Use string splitting to cut the input up and then loop through that list with for, while, do, until, or etc.
Create a sum total variable and add each input value to it, e.g. sum = sum + split_input[index], or if it will only allow a single input at a time sum = sum + input.
Some Notes:
Adding a value to a variable can be shortened to variable += value to add a value to an existing variable and assign the result to the variable, but not all languages support this syntax.
Not all programming languages start at 0 for list indices, so be sure to change the starting index accordingly.

XPath :: running counter two levels

Using the count(preceding-sibling::*) XPath expression one can obtaining incrementing counters. However, can the same also be accomplished in a two-levels deep sequence?
example XML instance
<grandfather>
<father>
<child>a</child>
</father>
<father>
<child>b</child>
<child>c</child>
</father>
</grandfather>
code (with Saxon HE 9.4 jar on the CLASSPATH for XPath 2.0 features)
Trying to get an counter sequence of 1,2 and 3 for the three child nodes with different kinds of XPath expressions:
XPathExpression expr = xpath.compile("/grandfather/father/child");
NodeList nodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
for (int i = 0 ; i < nodes.getLength() ; i++) {
Node node = nodes.item(i);
System.out.printf("child's index is: %s %s %s, name is: %s\n"
,xpath.compile("count(preceding-sibling::*)").evaluate(node)
,xpath.compile("count(preceding-sibling::child)").evaluate(node)
,xpath.compile("//child/position()").evaluate(doc)
,xpath.compile(".").evaluate(node));
}
The above code prints:
child's index is: 0 0 1, name is: a
child's index is: 0 0 1, name is: b
child's index is: 1 1 1, name is: c
None of the three XPaths I tried managed to produce the correct sequence: 1,2,3. Clearly it can trivially be done using the i loop variable but I want to accomplish it with XPath if possible. Also I need to keep the basic framework of evaluating an XPath expression to get all the nodes to visit and then iterating on that set since that's the way the real application I work on is structured. Basically I visit each node and then need to evaluate a number of XPath expressions on it (node) or on the document (doc); one of these XPAth expressions is supposed to produce this incrementing sequence.
Use the preceding axis with a name test instead.
count(preceding::child)
Using XPath 2.0, there is a much better way to do this. Fetch all <child/> nodes and use the position() function to get the index:
//child/concat("child's index is: ", position(), ", name is: ", text())
You don't say efficiency is important, but I really hate to see this done with O(n^2) code! Jens' solution shows how to do that if you can use the result in the form of a sequence of (position, name) pairs. You could also return an alternating sequence of strings and numbers using //child/(string(.), position()): though you would then want to use the s9api API rather than JAXP, because JAXP can only really handle the data types that arise in XPath 1.0.
If you need to compute the index of each node as part of other processing, it might still be worth computing the index for every node in a single initial pass, and then looking it up in a table. But if you're doing that, the simplest way is surely to iterate over the result of //child and build a map from nodes to the sequence number in the iteration.

xquery- how to obtain min/max value from a set of values that are obtained by subtracting consecutive members from a list

In an xquery expression, I have obtained a set of values within a for-expression, and one value is in a separate variable.
Now, I want to subtract the single value from first value of the list, and then subtract consecutive members of the list from each other-- and in the resulting set of difference values, I want to obtain the min/max values...
The query upto now looks like this--
let $value1:= 1998
let $rows_citations:=
$doc//div[#id="patent_citations"]
/div[#id="patent_citations_v"]
/table[#class="rel_patent"]
/tbody/tr[1]
/following-sibling::tr
for $pos in $rows_citations/position()
let $date2_c := customfn:dateconverter1($rows_citations[$pos]/td[3])
Now the subtraction I want is between first value of date2_c and value 1, and after that between consecutive members of date2_c... And from the resulting list I want the min/max values... How do I go about doing this?
I am esp. confused about creating a new list variable that stores all the differences, esp. when we are already inside a for loop, and are iterating over each value of a list (via variable date2_c)
I. This XQuery 3.0 query (which is also a pure XPath 3.0 expression):
let $pVal := 1,
$vList := (2,4,7,11,16),
$vList2 := ($pVal, subsequence($vList, 1, count($vList)-1)),
$vSubtactedList :=
map-pairs(function($m as xs:integer, $n as xs:integer) as xs:integer
{
$m - $n
},
$vList,
$vList2
)
return
(min($vSubtactedList), max($vSubtactedList))
produces the wanted result the minimum and maximum values from the list of subtractions:
1 5
II. XQuery 1.0 solution:
let $pVal := 1,
$vList := (2,4,7,11,16),
$vList2 := ($pVal, subsequence($vList, 1, count($vList)-1)),
$vSubtactedList :=
for $i in 1 to count($vList)
return
$vList[$i] - $vList2[$i]
return
(min($vSubtactedList), max($vSubtactedList))
This again produces the same correct result:
1 5

Print array length for each element of an array

Given a string array of variable length, print the lengths of each element in the array.
For example, given:
string[] ex = {"abc", "adf", "df", "ergd", "adfdfd");
The output should be:
2 3 4 6
One possibility I'm considering is to use a linked list to save each string length, and sort while inserting and finally display the results.
Any other suggestions for efficient solutions to this problem?
Whenever you want to maintain a collection of distinct things (ie: filter out duplicates), you probably want a set.
There are many different data structures for storing sets. Some of these, like search trees, will also "sort" the values for you. You could try using one of the many forms of binary search trees.
What you are doing now (or the given answer) is called the insertion sort. It basically compare the length of the string-to-insert from the inserted strings. After then, when printing, teh length of string-to-print (at current pointer) will be compared to the length of the string before it and after it, if has the same length, do not print!
Another approach is, the bubble sort, it will sort two strings at a time, sort them, then move to next string...
The printing is the most important part in your program, regardless of what sorting algorithm you use, it doesn't matter.
Here's an algorithm for bubble sort and printing process, it's VB so just convert it...
Dim YourString(4) As String
YourString(0) = "12345" 'Will not be printed
YourString(1) = "12345" 'Will not be printed
YourString(2) = "123" 'Will be printed
YourString(3) = "1234" 'Will be printed
Dim RoundLimit As Integer = YourString.Length - 2
'Outer loop for how many times we will sort the whole array...
For CycleCounter = 0 To RoundLimit
Dim CompareCounter As Integer
'Inner loop to compare strings...
For CompareCounter = 0 To RoundLimit - CycleCounter - 1
'Compare lengths... If the first is greater, sort! Note: this is ascending
If YourString(CompareCounter).Length > YourString(CompareCounter + 1).Length Then
'Sorting process...
Dim TempString = YourString(CompareCounter)
YourString(CompareCounter) = YourString(CompareCounter + 1)
YourString(CompareCounter + 1) = TempString
End If
Next
Next
'Cycles = Array length - 2 , so we have 2 cycles here
'First Cycle!!!
'"12345","12345","123","1234" Compare 1: index 0 and 1 no changes
'"12345","123","12345","1234" Compare 2: index 1 and 2 changed
'"12345","123","1234","12345" Compare 3: index 2 and 3 changed
'Second Cycle!!!
'"123","12345","1234","12345" Compare 1: index 0 and 1 changed
'"123","1234","12345","12345" Compare 2: index 1 and 2 changed
'"123","1234","12345","12345" Compare 3: index 2 and 3 no changes
'No more cycle!
'Now print it! Or use messagebox...
Dim CompareLimit As Integer = YourString.Length - 2
For CycleCounter = 0 To CompareLimit
'If length is equal to next string or the preceeding string, do not print...
If ((CycleCounter - 1) <> -1) Then 'Check if index exist
If YourString(CycleCounter).Length = YourString(CycleCounter - 1).Length Then
Continue For 'The length is not unique, exit compare, go to next iteration...
End If
End If
If ((CycleCounter + 1) <> YourString.Length - 1) Then 'Check if index exist
If YourString(CycleCounter).Length = YourString(CycleCounter + 1).Length Then
Continue For 'The length is not unique, exit compare, go to next iteration...
End If
End If
'All test passed, the length is unique, show a dialog!
MsgBox(YourString(CycleCounter))
Next
The question as stated doesn't say anything about sorting or removing duplicates from the results. It is only the given output that implies the sorting and duplicate removal. It doesn't say anything about optimisation for speed or space or writing for maintainability.
So there really isn't enough information for a "best" solution.
If you want a solution that will work in most languages you probably should stick with an array. Put the lengths in a new array, sort it, then print in a loop that remembers that last value to skip duplicates. I wouldn't want to use a language that couldn't cope with that.
If a language is specified you might be able to take advantage of set or associate array type data structures to handle the duplicates and/or sorting automatically. E.g., in Java you could pick a collection class that automatically ignores duplicates and sorts, and you could structure your code such that a one line change to use a different class would let you keep duplicates, or not sort. If you are using C# you could probably write the whole thing as a one-line LINQ statement...
Here is a C++ solution:
#include <set>
#include <vector>
#include <string>
#include <iostream>
using namespace std;
int main()
{
string strarr[] = {"abc", "adf", "df", "ergd", "adfsgf"};
vector< string > vstr(strarr, strarr + 5);
set< size_t > s;
for (size_t i = 0; i < vstr.size(); i++)
{
s.insert( vstr[i].size() );
}
for (set<size_t>::iterator ii = s.begin(); ii != s.end(); ii++)
cout << *ii << " ";
cout << endl;
return 0;
}
Output:
$ g++ -o set-str set-str.cpp
$ ./set-str
2 3 4 6
A set is used because (quoting from here):
Sets are a kind of associative container that stores unique elements,
and in which the elements themselves are the keys.
Associative containers are containers especially designed to be
efficient accessing its elements by their key (unlike sequence
containers, which are more efficient accessing elements by their
relative or absolute position).
Internally, the elements in a set are always sorted from lower to
higher following a specific strict weak ordering criterion set on
container construction.
Sets are typically implemented as binary search trees.
And for details on vector see here and here for string.
Depending on the language, the easiest way might be to iterate through the array using a for loop
for (i=0;i<array.length;i++){
print array[i].length;
}
do you need to print them in order?

Resources