I face a problem on how to store a list or a number into an empty array, below is my code :
For( i = 1, i <= N Items( S ), i++,
dt:Family Device << set name( "family device" );
dt << Select Where(Starts With( dt:family device, S[i] ) ) ;
baseDT = dt << Subset( output table name( "Subset" ), selected rows( 1 ), selected columns( 0 ), "invisible");
I plan to store baseDT in the empty array, Anyone has an idea on the store function? I very new to JSL if in python we will use append function to store, then how about jsl?
Initialize an empty array as
emp_array = {};
Append to array as :
Insert Into(emp_array, baseDT)
Then you can access the elements using index eg:
emp_array[n]
Related
I have this expression
vOther_OS =
CALCULATE (
SUM ( OS_excel[OS_AMOUNT] ),
Claims_excel[COVER_NAME]={"abc", "def"},Premium_Excel[LOB]="Caar"
)
when i try above expression this shows an error
"A table of multiple values was supplied where a single value was expected"
so this message clearly shows there should 1 value in bracket where i want more than 1 value
as i do this in qliksense expression
sum({<COVER_NAME -= {"abc", "def"},LOB = {'Caar'}>}OS_AMOUNT)
Change your formula to:
vOther_OS =
CALCULATE (
SUM ( OS_excel[OS_AMOUNT] ),
Claims_excel[COVER_NAME] IN { "abc", "def" },
Premium_Excel[LOB] = "Caar"
)
I've got a small problem.
I made calculations and all my ids are not following each other anymore (because of some delete during the calculus). Unfortunately, to make my result valid, I need this order... :/
So in order to simply the task, I made an external function, that will "rename" all the IDs but I do not know how to perform this.
Here is the function that I've got :
fun setId (W {id, ...}) =
let
in
print( "[" ^ Int.toString (id) ^ "]");
print( "[" ^ Int.toString (!nextId) ^ "]\n");
Ref.incr nextId
end
(for the one who are wandering appis just a homemade function to perform the same calcul on each element of a list, but it's not important.)
When I'm execute this code, I obtain in output :
[0][0]
[1][1]
[2][2]
[3][3]
[4][4]
[5][5]
[6][6]
[7][7]
[8][8]
[9][9]
[10][10]
[11][11]
[12][12]
[13][13]
[14][14]
[15][15]
[16][16]
[17][17]
[18][18]
[19][19]
[20][20]
[21][21]
[22][22]
[39][23]
[40][24]
[41][25]
[42][26]
[43][27]
[44][28]
[45][29]
[46][30]
[47][31]
[48][32]
[49][33]
[50][34]
[51][35]
[52][36]
[53][37]
as you can see there is a big problem [23] [39] the list does not have following numbers. :/
Basically, I would like the function setIdto be able to modify the ID of the Node. But I don't know how :/
Here is the datatype Node for understanding purposes :
datatype node =
W of {
id : int
, predId : int option
, creationDepcy : Dependency.depcy
, nominalDepcies : Dependency.depcy list ref
, pattern : Termstore.store
, propositions : Propstore.pstore
, nominals : Propstore.pstore
, diamonds : Termstore.store
, boxes : Termstore.store
, disjunctions : Termstore.store
, nglstore : Termstore.store
, lazyProps : Lazystore.store
, lazyNoms : Lazynomstore.store
, lazyBoxes : Lazyboxstore.store
, blockedDiamonds : (Term.index * int) list ref
, branchPoints : int list ref
}
Thanks in advance for your help !
Best Regards.
Since id is typed int it cannot be modified. If you change it to int ref then you can modify it, but you will also have to change the accessors to dereference the ref.
An alternative solution is to create an array that maps from old IDs to new IDs and use this array for presentation, but that seems even more complicated.
Since ints are immutable -- you could take your list of nodes and replace it with a new list of nodes:
fun newID (W(x), i) =
W({
id = i
, predId = #predId x
, creationDepcy = #creationDepcy x
, nominalDepcies = #nominalDepcies x
, pattern = #pattern x
, propositions = #propositions x
, nominals = #nominals x
, diamonds = #diamonds x
, boxes = #boxes x
, disjunctions = #disjunctions x
, nglstore = #nglstore x
, lazyProps = #lazyProps x
, lazyNoms = #lazyNoms x
, lazyBoxes = #lazyBoxes x
, blockedDiamonds = #blockedDiamonds x
, branchPoints = #branchPoints x
});
fun imap _ [] _ = []
| imap f (x::xs) i = f(x,i):: (imap f xs (i+1));
(imap stands for "increment map")
Then if xs is a list of nodes the function call
imap newID xs 0
will yield a new list of nodes with the id fields consecutive ints starting with 0
Disclaimer: I didn't try this on your setup of course, by I created a datatype of records which had an id field and successfully used this approach. Obviously this isn't something you would want to do a lot of because of all the copying, but if it is at one specific point in your code it should be okay.
Mostly equivalent to John's solution, here is how one would update a list of nodes without using references, using a fold instead. The function setId is the same.
fun setIds firstId ws =
#1 (foldr (fn (w,(ws',nextId)) => (setId w nextId::ws', nextId+1)) ([],firstId) ws)
Running setIds 1 [w1, w2, w3, ...] would yield [w1', w2', w3', ...].
Lets say I have a table like so:
{
value = 4
},
{
value = 3
},
{
value = 1
},
{
value = 2
}
and I want to iterate over this and print the value in order so the output is like so:
1
2
3
4
How do I do this, I understand how to use ipairs and pairs, and table.sort, but that only works if using table.insert and the key is valid, I need to be loop over this in order of the value.
I tried a custom function but it simply printed them in the incorrect order.
I have tried:
Creating an index and looping that
Sorting the table (throws error: attempt to perform __lt on table and table)
And a combination of sorts, indexes and other tables that not only didn't work, but also made it very complicated.
I am well and truly stumped.
Sorting the table
This was the right solution.
(throws error: attempt to perform __lt on table and table)
Sounds like you tried to use a < b.
For Lua to be able to sort values, it has to know how to compare them. It knows how to compare numbers and strings, but by default it has idea how to compare two tables. Consider this:
local people = {
{ name = 'fred', age = 43 },
{ name = 'ted', age = 31 },
{ name = 'ned', age = 12 },
}
If I call sort on people, how can Lua know what I intend? I doesn't know what 'age' or 'name' means or which I'd want to use for comparison. I have to tell it.
It's possible to add a metatable to a table which tells Lua what the < operator means for a table, but you can also supply sort with a callback function that tells it how to compare two objects.
You supply sort with a function that receives two values and you return whether the first is "less than" the second, using your knowledge of the tables. In the case of your tables:
table.sort(t, function(a,b) return a.value < b.value end)
for i,entry in ipairs(t) do
print(i,entry.value)
end
If you want to leave the original table unchanged, you could create a custom 'sort by value' iterator like this:
local function valueSort(a,b)
return a.value < b.value;
end
function sortByValue( tbl ) -- use as iterator
-- build new table to sort
local sorted = {};
for i,v in ipairs( tbl ) do sorted[i] = v end;
-- sort new table
table.sort( sorted, valueSort );
-- return iterator
return ipairs( sorted );
end
When sortByValue() is called, it clones tbl to a new sorted table, and then sorts the sorted table. It then hands the sorted table over to ipairs(), and ipairs outputs the iterator to be used by the for loop.
To use:
for i,v in sortByValue( myTable ) do
print(v)
end
While this ensures your original table remains unaltered, it has the downside that each time you do an iteration the iterator has to clone myTable to make a new sorted table, and then table.sort that sorted table.
If performance is vital, you can greatly speed things up by 'caching' the work done by the sortByValue() iterator. Updated code:
local resort, sorted = true;
local function valueSort(a,b)
return a.value < b.value;
end
function sortByValue( tbl ) -- use as iterator
if not sorted then -- rebuild sorted table
sorted = {};
for i,v in ipairs( tbl ) do sorted[i] = v end;
resort = true;
end
if resort then -- sort the 'sorted' table
table.sort( sorted, valueSort );
resort = false;
end
-- return iterator
return ipairs( sorted );
end
Each time you add or remove an element to/from myTable set sorted = nil. This lets the iterator know it needs to rebuild the sorted table (and also re-sort it).
Each time you update a value property within one of the nested tables, set resort = true. This lets the iterator know it has to do a table.sort.
Now, when you use the iterator, it will try and re-use the previous sorted results from the cached sorted table.
If it can't find the sorted table (eg. on first use of the iterator, or because you set sorted = nil to force a rebuild) it will rebuild it. If it sees it needs to resort (eg. on first use, or if the sorted table was rebuilt, or if you set resort = true) then it will resort the sorted table.
I am creating a JSL script for some of my datatables and need my function to act on a column.
I can get the function to act on the column during a plotting event, but not with standard operations.
Here's an example that works. This acts on the current datatable and plots up the Distribution for :Column1, which happens to be Nominal Character with 4 unique items in it.
a = Function(
{col}, // Function parameters
{Default Local}, // Local variables
Distribution(
Nominal Distribution(
Column( col ),
Horizontal Layout( 1 ),
Vertical( 0 )
);
);
);
dt = Current Data Table();
a(Expr(:Column1));
Note the Expr() around :Column1. Without this, the Distribution function does not work.
What I'm trying to do is the following, but it doesn't work. What it should do is show the number of unique items in :Column1.
a = Function(
{col}, // Function parameters
{Default Local}, // Local variables
retval = associative array(col);
Show(nitems(retval));
);
dt = Current Data Table();
a(Expr(:Column1));
Returns in Log Window:
N Items(retval) = 0; // Should be 4
If I run the script without trying to wrap it in a function, then it works just fine:
retval = associative array(:Column1);
Show(nitems(retval));
Returns in Log Window:
N Items(retval) = 4; // My column happens to have 4 unique entries in it.
I'm fairly certain that my issue has something to do with namespace inside the function, but I can't seem to figure it out. Does anyone have any suggestions?
It is (from what I've seen) just an issue with the scoping operator : in :Column1.
Try using
a = Function(
{col}, // Function parameters
{Default Local}, // Local variables
retval = associative array(col<<Get Values)<<Get Keys;
Show(nitems(retval));
);
dt = Current Data Table();
a(column(dt, "Column1"));
it returned
N Items(retval) = 9;
Given XML file-record like this
<ADR-NSBG>
<timeline timestamp="2011-06-09T00:15:00">
<datum datum="SGC_at_bsNo-14___SignalingNetworkConnection_at_netId-4___Sip_at_networkRole-2">
<sbgSipTotalIncSipRequests>4314320</sbgSipTotalIncSipRequests>
<sbgSipTotalIncSipResponses>9040481</sbgSipTotalIncSipResponses>
<sbgSipTotalIncFailureResponses>2321242</sbgSipTotalIncFailureResponses>
<sbgSipTotalOutSipRequests>9136608</sbgSipTotalOutSipRequests>
<sbgSipTotalOutSipResponses>4643002</sbgSipTotalOutSipResponses>
<sbgSipTotalOutFailureResponses>1027420</sbgSipTotalOutFailureResponses>
<sbgSipIncommingProvisionalResponses>3433875</sbgSipIncommingProvisionalResponses>
<sbgSipOutgoingProvisionalResponses>1845750</sbgSipOutgoingProvisionalResponses>
</datum>
<datum datum="SGC_at_bsNo-13___SignalingNetworkConnection_at_netId-4___Sip_at_networkRole-2">
<sbgSipTotalIncSipRequests>4799739</sbgSipTotalIncSipRequests>
<sbgSipTotalIncSipResponses>9335965</sbgSipTotalIncSipResponses>
<sbgSipTotalIncFailureResponses>2415690</sbgSipTotalIncFailureResponses>
<sbgSipTotalOutSipRequests>9474295</sbgSipTotalOutSipRequests>
<sbgSipTotalOutSipResponses>5291708</sbgSipTotalOutSipResponses>
<sbgSipTotalOutFailureResponses>1149950</sbgSipTotalOutFailureResponses>
<sbgSipIncommingProvisionalResponses>3516298</sbgSipIncommingProvisionalResponses>
<sbgSipOutgoingProvisionalResponses>2190601</sbgSipOutgoingProvisionalResponses>
</datum>
</timeline>
</ADR-NSBG>
What I would like to do is to get the values of the children of the datum element.
so, I have written the following query:
for $i in collection("/db/_DEMO/ADR-NSBG/sipTransactTM/2011/06/09")
let $TIME_FROM := "2011-06-09T00:15:00"
let $TIME_TO := "2011-06-09T00:45:00"
let $DATUM := "SGC_at_bsNo-13___SignalingNetworkConnection_at_netId-4___Sip_at_networkRole-2"
where ( $i/ADR-NSBG/timeline/#timestamp/string(.) >= $TIME_FROM and
$i/ADR-NSBG/timeline/#timestamp/string(.) <= $TIME_TO) and
( $i/ADR-NSBG/timeline/datum/#datum/string(.) = $DATUM )
order by $i/ADR-NSBG/timeline/#timestamp/string(.)
return $i/ADR-NSBG/timeline/datum
But, the problem is that I cannot choose between the two "datum" nodes.
the result of the query is:
<datum datum="SGC_at_bsNo-14___SignalingNetworkConnection_at_netId-4___Sip_at_networkRole-2">
<sbgSipTotalIncSipRequests>4314320</sbgSipTotalIncSipRequests>
<sbgSipTotalIncSipResponses>9040481</sbgSipTotalIncSipResponses>
<sbgSipTotalIncFailureResponses>2321242</sbgSipTotalIncFailureResponses>
<sbgSipTotalOutSipRequests>9136608</sbgSipTotalOutSipRequests>
<sbgSipTotalOutSipResponses>4643002</sbgSipTotalOutSipResponses>
<sbgSipTotalOutFailureResponses>1027420</sbgSipTotalOutFailureResponses>
<sbgSipIncommingProvisionalResponses>3433875</sbgSipIncommingProvisionalResponses>
<sbgSipOutgoingProvisionalResponses>1845750</sbgSipOutgoingProvisionalResponses>
</datum>
<datum datum="SGC_at_bsNo-13___SignalingNetworkConnection_at_netId-4___Sip_at_networkRole-2">
<sbgSipTotalIncSipRequests>4799739</sbgSipTotalIncSipRequests>
<sbgSipTotalIncSipResponses>9335965</sbgSipTotalIncSipResponses>
<sbgSipTotalIncFailureResponses>2415690</sbgSipTotalIncFailureResponses>
<sbgSipTotalOutSipRequests>9474295</sbgSipTotalOutSipRequests>
<sbgSipTotalOutSipResponses>5291708</sbgSipTotalOutSipResponses>
<sbgSipTotalOutFailureResponses>1149950</sbgSipTotalOutFailureResponses>
<sbgSipIncommingProvisionalResponses>3516298</sbgSipIncommingProvisionalResponses>
<sbgSipOutgoingProvisionalResponses>2190601</sbgSipOutgoingProvisionalResponses>
</datum>
What I would like to ask you is : Why the statement ( $i/ADR-NSBG/timeline/datum/#datum/string(.) = $DATUM ) does not work ?
Whithin the where clause you are filtering the $i elements of the for clause by using the datum element. You are not filtering the datum elements.
This expression:
( $i/ADR-NSBG/timeline/datum/#datum/string(.) = $DATUM )
is resolved to:
(
"SGC_at_bsNo-14___SignalingNetworkConnection_at_netId-4___Sip_at_networkRole-2",
"SGC_at_bsNo-13___SignalingNetworkConnection_at_netId-4___Sip_at_networkRole-2"
) =
"SGC_at_bsNo-13___SignalingNetworkConnection_at_netId-4___Sip_at_networkRole-2"
which is true. Therefore, the $i element is selected. After that, the expression in the return clause selects both child elements of the contained timeline element:
$i/ADR-NSBG/timeline/datum
How to filter the datum elements
If you want to select only the datum with a specific string, you need to filter in the return clause:
$i/ADR-NSBG/timeline/datum[#datum eq $DATUM]