Creating sublists of arbitrary grouping - raku

I'm trying to group several items from a list of strings based on the first part of each string (i.e. the part before the first tab if there is a tab or the whole string if there isn't a tab).
This works:
use Test;
my #lines = "A\tFoo"
, "A\tBar"
, "B"
, "B"
, "A\tBaz"
, "B"
;
my #expected = ["A\tFoo", "A\tBar"]
, ["B", "B"]
, ["A\tBaz"]
, ["B"]
;
my #result = group-lines(#lines);
is #result, #expected, "Grouped correctly";
sub group-lines (#records) {
my #groups;
my #current-records;
my $last-type;
for #records -> $record {
my $type = $record.split("\t")[0];
once { $last-type = $type }
if $type ne $last-type {
#groups.push: [#current-records];
#current-records = ();
}
#current-records.push: $record;
LAST { #groups.push: [#current-records] }
}
return #groups;
}
But it seems so verbose. Isn't there a shorter way to do this in Perl 6? Please note that I only want to group like items that are consecutive members of the original list.
(update) The order within groups is important.
UPDATE
Here is a more numerically oriented example. It groups numbers based on divisibility of subsequent numbers by the first number.
#!/bin/env perl6
use Test;
my #numbers = 2, 4, 6, 3, 6, 9, 12, 14;
my #expected = [2, 4, 6], [3, 6, 9, 12], [14];
my #result = group-nums(#numbers);
is #result, #expected, "Grouped correctly";
sub group-nums (#numbers) {
my #groups;
my #current-group;
my $denominator = #numbers[0];
for #numbers -> $num {
if $num % $denominator {
#groups.push: [#current-group];
#current-group = ();
}
#current-group.push: $num;
}
#groups.push: [#current-group];
return #groups;
}

You can use categorize (or categorize-list, or the classify variations if you want elements to be present in more than one category). Since your groupings are dynamic, depending on the keys that have come before, use a state variable to remember what has come before. The second example is easy because while the order matters, it's not prevented from re-adding elements to an older group:
my #numbers = <2 4 6 3 6 9 12 14>;
#numbers.classify: {
state $denom = $_; if $_ !%% $denom { $denom = $_ }; $denom;
};
# result: {2 => [2 4 6], 3 => [3 6 9 12], 14 => [14]}
Your first example needs to distinguish each grouping from groupings that came before, so the quick and dirty way is to index each group, so you can have two A groups:
my %result = #lines.classify: {
state $index = 0; # first group is group 0
state $prefix = .split("\t")[0]; # The first prefix is based on the first string
if !.starts-with($prefix) {
$prefix = .split("\t")[0]; # This is a new prefix. Remember it.
++$index; # start a new group
};
($index<> => $prefix<>); # Classify this element with a decontainerized pair. See note.
};
# result: {0 A => [A Foo A Bar], 1 B => [B B], 2 A => [A Baz], 3 B => [B]}
say %result.values; # output: ([B] [B B] [A Baz] [A Foo A Bar])
Do you need these to be in order? Since these two methods use hashes to store the data, the result is unordered.
Note: I used the <> operator to explicitly decontainerize the values that go into the Pair which is used as the classification value. Since this value is a hash key, without decontainerizing, the object ID (technically the .WHICH value) is used for hashing, and you will find that given $one = 1, (a => 1).WHICH !eqv (a => $one).WHICH. Hence, you remove the containers so the pair is treated as a pair of plain values, which will have the same hash key.
Note 2: The classification keys can be lists, which will result in a nested data structure. You won't need to decontainerize the keys, and you won't need to worry about forgetting the order. The only annoyance is an extra level of nesting in the output. To get a nested result, your classification key would be ($index, $prefix).

Here is a bit of functionally-inspired solution, though maybe a bit convoluted:
use Test;
my #lines = "A\tFoo"
, "A\tBar"
, "B"
, "B"
, "A\tBaz"
, "B"
;
my #expected = ["A\tFoo", "A\tBar"]
, ["B", "B"]
, ["A\tBaz"]
, ["B"]
;
my #eq = #lines.map(*.split("\t")[0]).rotor(2 => -1).map({ [eq] .list});
my #result = [#lines[0],],;
for #lines[1..*] Z #eq -> ($line, $eq) {
#result.push([]) unless $eq;
#result[*-1].push: $line;
}
plan 1;
is-deeply #result, #expected;
The idea is that #eq contains for each position (except the first) a True if the previous element has the same prefix as the current one.
But we don't pretend that Lisp is the One True God, and car and cdr are Her prophets, we can inline that decision, simply by using the array index to access the previous element when we need it:
my #result;
for #lines.kv -> $idx, $elem {
#result.push([]) if $idx == 0 || $elem.split("\t")[0] ne #lines[$idx-1].split("\t")[0];
#result[*-1].push: $elem;
}
plan 1;
is-deeply #result, #expected;

Related

Is there an easy way to multiply each element with each other in array / list - Kotlin?

I have got {1,2,3} / or it might be a list<Int> is there an easy way to multiply each element with each other like 1*2 , 1*3, 2*3 ?
This should work, given that you probably don't want to include the duplicates like items[i] * items[j] and items[j] * items[i]
val items = listOf(1, 2, 3, 4)
val result = items.flatMapIndexed { index, a ->
items.subList(index + 1, items.size).map { b -> a * b }
}
println(result) // [2, 3, 4, 6, 8, 12]
flatMapIndexed builds a list for each of the items elements by evaluating the lambda on the index and the item, and then concatenates the lists.
subList is an efficient way to take the items in the specific range: starting at the next index, and until the end of the list.
You can try the old-fashioned way: nested loops
fun main(args: Array<String>) {
val list = listOf( 1, 2, 3 )
for (i in list.indices) {
for (j in (i + 1) until list.size) {
println("${list[i]} * ${list[j]} = ${list[i] * list[j]}")
}
}
}
Output of this code:
1 * 2 = 2
1 * 3 = 3
2 * 3 = 6
If you did want all the permutations (every possible ordering), you could do something like this:
val result = with(items) {
flatMapIndexed { i, first ->
slice(indices - i).map { second -> // combine first and second here }
}
}
slice lets you provide a list of indices for the elements you want to pull, so you can easily exclude the current index and get all the other elements to combo it with. Takes an IntRange too, so you can do slice(i+1 until size) to get the combination (every pairing) functionality too.
Not as efficient as hotkey's subList version (since that doesn't make a copy) but you can get two behaviours this way so I thought I'd mention it! But if I were making a reusable function rather than a quick one-liner, I'd probably go with deHaar's approach with the nested for loops, it's efficient and easy enough to tweak for either behaviour

Printing mathematical series concisely in Raku

Mathematical series, take for example the consecutive sequence represented here as an array:
my #seq = my $a=0, {++$a} ... *;
for #seq[^10].kv {state $f=0; ($^k < 4 or $^k > 7) ?? say "a$^k = " ~ $^v !! (say "..." if $f ne 1; $f=1) };
Prints:
a0 = 0
a1 = 1
a2 = 2
...
a8 = 8
a9 = 9
1- Is there a simple way to drop just the first element i.e. a0 = 0 from the printed output?
2- Could this code be made more idiomatic?
This might be a bit more idiomatic:
my #seq = 0, *+1 ... *;
say #seq[^4], #seq[7..10]
You don't need to use a lexical variable within the sequence; either Whatever or placeholder variables can safely be used within sequences. Then you can simply select the elements of the sequence you want printed.
Which returns «(0 1 2 3)(7 8 9 10)␤»
You can skip the first N values on any Iterable or Sequence with skip:
for (^5).skip(3) {
.say
}
# 3
# 4
If you don't specify a number, it will skip only one element.
A barebones solution
Let's start with a very simple solution for printing a gist of a sequence. It doesn't deal with the specifics you've added to your question but it's a good starting point:
sub seq-range-gist ( #seq ) {
my #pairs = #seq.pairs;
join "\n", #pairs.head(3)».gist, '...', #pairs.tail(2)».gist
}
Unlike .kv, which converts its invocant into the form key1, value1, key2, value2, key3, value3, ..., i.e. 6 elements if its invocant contains 3 elements, .pairs converts its invocant into the form key1 => value1, key2 => value2, key3 => value3, ....
I used .pairs instead of .kv partly because it meant I could just use ».gist later on in the code to effortlessly get a nice key1 => value1 display for each element. We'll modify that below but this is a good idiomatic start.
The .head and .tail calls are the idiomatic way to create small lists of the first and last N elements from an invocant list (provided it's not lazy; more about that in a mo).
Given this initial solution, say seq-range-gist (0,1 ... Inf)[^10] displays:
0 => 0
1 => 1
2 => 2
...
8 => 8
9 => 9
Next, we want to be able to "drop just the first element ... from the printed output". Unfortunately say seq-range-gist (0,1 ... Inf)[1..9] displays:
0 => 1
1 => 2
2 => 3
...
7 => 8
8 => 9
We want the number on the left of the => to retain the numbering of the original sequence. To enable this we split the underlying sequence from the range that we want extracted. We add a second parameter/argument #range, and append [#range] to the second line of the sub:
sub seq-range-gist ( #seq, #range ) {
my #pairs = #seq.pairs[#range];
Now we can write say seq-range-gist (0,1 ... Inf), 1..9 to display:
1 => 1
2 => 2
3 => 3
...
8 => 8
9 => 9
In your question you used the format aINDEX = VALUE rather than INDEX => VALUE. To allow customization of the gist, we add a third &gist routine parameter/argument and invoke that instead of the built in .gist method:
sub seq-range-gist ( #seq, #range, :&gist ) {
my #pairs = #seq.pairs[#range];
join "\n", #pairs.head(3)».&gist, '...', #pairs.tail(2)».&gist
}
Note how the "method" invocations in the body of seq-range-gist sub are now .&gist, not .gist. The syntax .&foo invokes a sub &foo (which is typically invoked by writing just foo), passing the invocant on the left of the . as a $_ argument to the sub.
Note also that I've made the &gist parameter a named one by preceding it with a :.
So now say seq-range-gist (0,1 ... Inf), 1..9, gist => { "a{.key} = {.value}" } displays:
a1 = 1
a2 = 2
a3 = 3
...
a8 = 8
a9 = 9
Adding polish
The rest of this answer is bonus material for readers who care about polish.
say seq-range-gist (0, 1, 2, 3), ^3 displays:
0 => 0
1 => 1
2 => 2
...
1 => 1
2 => 2
Oops. And even if there were more pairs than the head and tail combined, so at least we didn't get repeated lines, it'd still be pointless using the head, ..., tail approach to elide just one or two elements. Let's change the last statement in the sub body to eliminate these issues:
join "\n",
#pairs < $head + $tail + 3 # Of course, the 3 is a bit arbitrary
?? #pairs».&gist
!! (#pairs.head($head)».&gist, '...', #pairs.tail($tail)».&gist)
Next, it would be nice if the sub did something useful if called without a range or gist. We can mostly fix that by giving the #range and &gist parameters suitable defaults:
sub seq-range-gist (
#seq,
#range = #seq.is-lazy ?? ^100 !! ^#seq,
:&gist = { .gist }
) {
If #seq is not lazy, then #range defaults to the full range of #seq. If #seq is infinite (in which case it's also lazy), then the upto 100 default is fine. But what if #seq is lazy but yields less than 100 defined values? To cover this case we append .grep: *.value.defined to the #pairs declaration:
my #pairs = #seq.pairs[#range].grep: *.value.defined;
Another simple improvement would be optional head and tail parameters, leading to a final polished solution:
sub seq-range-gist (
#seq,
#range = #seq.is-lazy ?? ^100 !! ^#seq,
:$head = 3,
:$tail = 2,
:&gist = { .gist }
) {
my #pairs = #seq.pairs[#range].grep: *.value.defined;
join "\n",
#pairs <= $head + $tail + 2
?? #pairs».&gist
!! (#pairs.head($head)».&gist, '...', #pairs.tail($tail)».&gist)
}
my #seq = my $a=0, {++$a} ... *;
my \i = 0;
say( 'a' ~ (i+$_) Z=> (i+$_) ) for #seq[^5];
print "------\n";
my \j = 1;
say( 'a'.succ ~ (j+$_) Z=> (j+$_) ) for #seq[^5];
Output:
(a0 => 0)
(a1 => 1)
(a2 => 2)
(a3 => 3)
(a4 => 4)
------
(b1 => 1)
(b2 => 2)
(b3 => 3)
(b4 => 4)
(b5 => 5)
I recognize the above doesn't include your 'bespoke' gist ellipsis conditional ( ($^k < 4 or $^k > 7) ), but you seem to have come up with a more elegant way of writing that in the comments. Still (if you don't want to use skip), number keys yourself and include an offset such as i or j indicating how many elements of #seq you wish to skip.
Addendum: Below is an attempt at implementing your 'bespoke' gist ellipsis conditional (using grep):
my #seq = my $a=0, {++$a} ... *;
my \i = 0; my \m = 4; my \n = 7;
do for #seq[^10].grep({4 > $_ or $_ > 7 }) {
say 'a' ~ (i+$_) Z=> (i+$_);
if $_ == 3 {print "...\n"};
}
Output when \i = 0:
(a0 => 0)
(a1 => 1)
(a2 => 2)
(a3 => 3)
...
(a8 => 8)
(a9 => 9)
Output when \i = 1:
(a1 => 1)
(a2 => 2)
(a3 => 3)
(a4 => 4)
...
(a9 => 9)
(a10 => 10)

Specman/e list of lists (multidimensional array)

How can I create a fixed multidimensional array in Specman/e using varibles?
And then access individual elements or whole rows?
For example in SystemVerilog I would have:
module top;
function automatic my_func();
bit [7:0] arr [4][8]; // matrix: 4 rows, 8 columns of bytes
bit [7:0] row [8]; // array : 8 elements of bytes
row = '{1, 2, 3, 4, 5, 6, 7, 8};
$display("Array:");
foreach (arr[i]) begin
arr[i] = row;
$display("row[%0d] = %p", i, row);
end
$display("\narr[2][3] = %0d", arr[2][3]);
endfunction : my_func
initial begin
my_func();
end
endmodule : top
This will produce this output:
Array:
row[0] = '{'h1, 'h2, 'h3, 'h4, 'h5, 'h6, 'h7, 'h8}
row[1] = '{'h1, 'h2, 'h3, 'h4, 'h5, 'h6, 'h7, 'h8}
row[2] = '{'h1, 'h2, 'h3, 'h4, 'h5, 'h6, 'h7, 'h8}
row[3] = '{'h1, 'h2, 'h3, 'h4, 'h5, 'h6, 'h7, 'h8}
arr[2][3] = 4
Can someone rewrite my_func() in Specman/e?
There are no fixed arrays in e. But you can define a variable of a list type, including a multi-dimensional list, such as:
var my_md_list: list of list of my_type;
It is not the same as a multi-dimensional array in other languages, in the sense that in general each inner list (being an element of the outer list) may be of a different size. But you still can achieve your purpose using it. For example, your code might be rewritten in e more or less like this:
var arr: list of list of byte;
var row: list of byte = {1;2;3;4;5;6;7;8};
for i from 0 to 3 do {
arr.add(row.copy());
print arr[i];
};
print arr[2][3];
Notice the usage of row.copy() - it ensures that each outer list element will be a copy of the original list.
If we don't use copy(), we will get a list of many pointers to the same list. This may also be legitimate, depending on the purpose of your code.
In case of a field (as opposed to a local variable), it is also possible to declare it with a given size. This size is, again, not "fixed" and can be modified at run time (by adding or removing items), but it determines the original size of the list upon creation, for example:
struct foo {
my_list[4][8]: list of list of int;
};

How to build lazy lists with defined generators and is there a "takeWhile" alternative?

I am reading through perl6intro on lazy lists and it leaves me confused about certain things.
Take this example:
sub foo($x) {
$x**2
}
my $alist = (1,2, &foo ... ^ * > 100);
will give me (1 2 4 16 256), it will square the same number until it exceeds 100. I want this to give me (1 4 9 16 25 .. ), so instead of squaring the same number, to advance a number x by 1 (or another given "step"), foo x, and so on.
Is it possible to achieve this in this specific case?
Another question I have on lazy lists is the following:
In Haskell, there is a takeWhile function, does something similar exist in Perl6?
I want this to give me (1 4 9 16 25 .. )
The easiest way to get that sequence, would be:
my #a = (1..*).map(* ** 2); # using a Whatever-expression
my #a = (1..*).map(&foo); # using your `foo` function
...or if you prefer to write it in a way that resembles a Haskell/Python list comprehension:
my #a = ($_ ** 2 for 1..*); # using an in-line expression
my #a = (foo $_ for 1..*); # using your `foo` function
While it is possible to go out of one's way to express this sequence via the ... operator (as Brad Gilbert's answer and raiph's answer demonstrate), it doesn't really make sense, as the purpose of that operator is to generate sequences where each element is derived from the previous element(s) using a consistent rule.
Use the best tool for each job:
If a sequence is easiest to express iteratively (e.g. Fibonacci sequence):
Use the ... operator.
If a sequence is easiest to express as a closed formula (e.g. sequence of squares):
Use map or for.
Here is how you could write a Perl 6 equivalent of Haskell's takewhile.
sub take-while ( &condition, Iterable \sequence ){
my \iterator = sequence.iterator;
my \generator = gather loop {
my \value = iterator.pull-one;
last if value =:= IterationEnd or !condition(value);
take value;
}
# should propagate the laziness of the sequence
sequence.is-lazy
?? generator.lazy
!! generator
}
I should probably also show an implementation of dropwhile.
sub drop-while ( &condition, Iterable \sequence ){
my \iterator = sequence.iterator;
GATHER: my \generator = gather {
# drop initial values
loop {
my \value = iterator.pull-one;
# if the iterator is out of values, stop everything
last GATHER if value =:= IterationEnd;
unless condition(value) {
# need to take this so it doesn't get lost
take value;
# continue onto next loop
last;
}
}
# take everything else
loop {
my \value = iterator.pull-one;
last if value =:= IterationEnd;
take value
}
}
sequence.is-lazy
?? generator.lazy
!! generator
}
These are only just-get-it-working examples.
It could be argued that these are worth adding as methods to lists/iterables.
You could (but probably shouldn't) implement these with the sequence generator syntax.
sub take-while ( &condition, Iterable \sequence ){
my \iterator = sequence.iterator;
my \generator = { iterator.pull-one } …^ { !condition $_ }
sequence.is-lazy ?? generator.lazy !! generator
}
sub drop-while ( &condition, Iterable \sequence ){
my \end-condition = sequence.is-lazy ?? * !! { False };
my \iterator = sequence.iterator;
my $first;
loop {
$first := iterator.pull-one;
last if $first =:= IterationEnd;
last unless condition($first);
}
# I could have shoved the loop above into a do block
# and placed it where 「$first」 is below
$first, { iterator.pull-one } … end-condition
}
If they were added to Perl 6/Rakudo, they would likely be implemented with Iterator classes.
( I might just go and add them. )
A direct implementation of what you are asking for is something like:
do {
my $x = 0;
{ (++$x)² } …^ * > 100
}
Which can be done with state variables:
{ ( ++(state $x = 0) )² } …^ * > 100
And a state variable that isn't used outside of declaring it doesn't need a name.
( A scalar variable starts out as an undefined Any, which becomes 0 in a numeric context )
{ (++( $ ))² } …^ * > 100
{ (++$)² } …^ * > 100
If you need to initialize the anonymous state variable, you can use the defined-or operator // combined with the equal meta-operator =.
{ (++( $ //= 5))² } …^ * > 100
In some simple cases you don't have to tell the sequence generator how to calculate the next values.
In such cases the ending condition can also be simplified.
say 1,2,4 ...^ 100
# (1 2 4 8 16 32 64)
The only other time you can safely simplify the ending condition is if you know that it will stop on the value.
say 1, { $_ * 2 } ... 64;
# (1 2 4 8 16 32 64)
say 1, { $_ * 2 } ... 3;
# (1 2 4 8 16 32 64 128 256 512 ...)
I want this to give me (1 4 9 16 25 .. )
my #alist = {(++$)²} ... Inf;
say #alist[^10]; # (1 4 9 16 25 36 49 64 81 100)
The {…} is an arbitrary block of code. It is invoked for each value of a sequence when used as the LHS of the ... sequence operator.
The (…)² evaluates to the square of the expression inside the parens. (I could have written (…) ** 2 to mean the same thing.)
The ++$ returns 1, 2, 3, 4, 5, 6 … by combining a pre-increment ++ (add one) with a $ variable.
In Haskell, there is a takeWhile function, does something similar exist in Perl6?
Replace the Inf from the above sequence with the desired end condition:
my #alist = {(++$)²} ... * > 70; # stop at step that goes past 70
say #alist; # [1 4 9 16 25 36 49 64 81]
my #alist = {(++$)²} ...^ * > 70; # stop at step before step past 70
say #alist; # [1 4 9 16 25 36 49 64]
Note how the ... and ...^ variants of the sequence operator provide the two variations on the stop condition. I note in your original question you have ... ^ * > 70, not ...^ * > 70. Because the ^ in the latter is detached from the ... it has a different meaning. See Brad's comment.

Is there a way to simplify incremental calculations in acrobat?

Other than using a long string of if statements is there a way to program an acrobat text box to incrementally calculate based on variables entered into an other text box?
Here is what I have.
var v = this.getField("FixNum").value;
if (v == "1")
{
event.value = 84 ;
}
else if (v == "2")
{
event.value = 88 ;
}
else if (v == "3")
{
event.value = 92 ;
}
else
{
event.value = "";
}
As you can see this will get cumbersome because this goes from 1 - 9 in this pattern where 9 = 116, then 10 - 100 where 10 = 135. After 100 the pattern is 495 + 6 for every unit i.e. 101 = 501. I hope someone can understand this because I can't think of another way to ask!
Several possibilities:
• If you can come up with a formula, it would be simplest.
• If the value pairs are arbitrary, you might create a lookup table (in form of an array).
• If the input numbers are (more or less) consecutive integers, you can work with a simple array, where the index is the input number, and the element with that index number is the output number.
• If it is more complicated, you would have to create a 2-dimensional array, where each element is an array of input and output number.
• If you are looking for a simple replacement of if…else if statements, you can use the switch… statement, which would work well for totally arbitrary value pairs.
Update, following the comment by OP:
According to a comment by the OP, the input numbers are consecutive, which means that the third point above would be the method of choice. For that, proceed as follows:
Create a document-level script (the name does not matter):
var myPricesArr = [0, 12, 15, 17, 23, 27, 30, 33] ;
alternate possibility:
var myPricesArr = new Array() ;
myPricesArr[0] = 0 ;
myPricesArr[1] = 12 ;
myPricesArr[2] = 15 ;
myPricesArr[3] = 17 ;
myPricesArr[4] = 23 ;
myPricesArr[5] = 27 ;
myPricesArr[6] = 30 ;
myPricesArr[7] = 33 ;
Both variants are equivalent, but the second one is easier to maintain, but requires more typing…
Create a text field named "numFixts", formatted as number, no decimals, maybe with a maximum value (to protect the form from failing).
Create a text field named "fixtsAmt, formatted as number. In the Calculate event of this field add the following JavaScript:
event.value = myPricesArr[this.getField("numFixts").value] ;
And that should do it.