I try this code
println(listOf(1, 2, 4).foldRight(0) { total, next ->
total - next
})
I thought it works like 0 + 4 - 2 - 1 = 1.
But it returns 3. Why?
Sorry for this silly question.
foldRight works by accumulating the result from right to left. In your case, it is going to do
(1 - (2 - (4 - 0))) = (1 - (2 - 4)) = 1 - (-2) = 3
Note that your operation has its parameters in the wrong order, foldRight will pass you the next element as the first parameter and the accumulator as the second parameter. See https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/fold-right.html. If you swap them, you would have
(((0 - 4) - 2) - 1) = - 7
unless I am getting something wrong
Related
I have a dataset with variables that start with category 'RC' and end wih a number that corresponds to a brand. The middle letter refers to a product.
For example:
RC_x_1 RC_b_1 RC_g_1 RC_x_2 RC_b_2 RC_g_2 etc.
Each variable has 5 values. I want to compute a new variable with all variables per brand that score within top 2 values.
So:
RC_x_1 (1 or 2) OR RC_b_1 (1 or 2) OR RC_g_1 (1 or 2) = RC_all_1
RC_x_2 (1 or 2) OR RC_b_2 (1 or 2) OR RC_g_2 (1 or 2) = RC_all_2
I tried some wild card options like:
If RC_""1 = 1 OR RC""_1 = 2 RC_all_1 =1.
But it doesn't work :) Any ideas how to create something like this?
Thanks mucho!
I'd like to find the contiguous sequences of equal elements (e.g. of length 2) in a list
my #s = <1 1 0 2 0 2 1 2 2 2 4 4 3 3>;
say grep {$^a eq $^b}, #s;
# ==> ((1 1) (2 2) (4 4) (3 3))
This code looks ok but when one more 2 is added after the sequence of 2 2 2 or when one 2 is removed from it, it says Too few positionals passed; expected 2 arguments but got 1 How to fix it? Please note that I'm trying to find them without using for loop, i.e. I'm trying to find them using a functional code as much as possible.
Optional: In the bold printed section:
<1 1 0 2 0 2 1 2 2 2 4 4 3 3>
multiple sequences of 2 2 are seen. How to print them the number of times they are seen? Like:
((1 1) (2 2) (2 2) (4 4) (3 3))
There are an even number of elements in your input:
say elems <1 1 0 2 0 2 1 2 2 2 4 4 3 3>; # 14
Your grep block consumes two elements each time:
{$^a eq $^b}
So if you add or remove an element you'll get the error you're getting when the block is run on the single element left over at the end.
There are many ways to solve your problem.
But you also asked about the option of allowing for overlapping so, for example, you get two (2 2) sub-lists when the sequence 2 2 2 is encountered. And, in a similar vein, you presumably want to see two matches, not zero, with input like:
<1 2 2 3 3 4>
So I'll focus on solutions that deal with those issues too.
Despite the narrowing of solution space to deal with the extra issues, there are still many ways to express solutions functionally.
One way that just appends a bit more code to the end of yours:
my #s = <1 1 0 2 0 2 1 2 2 2 4 4 3 3>;
say grep {$^a eq $^b}, #s .rotor( 2 => -1 ) .flat
The .rotor method converts a list into a list of sub-lists, each of the same length. For example, say <1 2 3 4> .rotor: 2 displays ((1 2) (3 4)). If the length argument is a pair, then the key is the length and the value is an offset for starting the next pair. If the offset is negative you get sub-list overlap. Thus say <1 2 3 4> .rotor: 2 => -1 displays ((1 2) (2 3) (3 4)).
The .flat method "flattens" its invocant. For example, say ((1,2),(2,3),(3,4)) .flat displays (1 2 2 3 3 4).
A perhaps more readable way to write the above solution would be to omit the flat and use .[0] and .[1] to index into the sub-lists returned by rotor:
say #s .rotor( 2 => -1 ) .grep: { .[0] eq .[1] }
See also Elizabeth Mattijsen's comment for another variation that generalizes for any sub-list size.
If you needed a more general coding pattern you might write something like:
say #s .pairs .map: { .value xx 2 if .key < #s - 1 and [eq] #s[.key,.key+1] }
The .pairs method on a list returns a list of pairs, each pair corresponding to each of the elements in its invocant list. The .key of each pair is the index of the element in the invocant list; the .value is the value of the element.
.value xx 2 could have been written .value, .value. (See xx.)
#s - 1 is the number of elements in #s minus 1.
The [eq] in [eq] list is a reduction.
If you need text pattern matching to decide what constitutes contiguous equal elements you might convert the input list into a string, match against that using one of the match adverbs that generate a list of matches, then map from the resulting list of matches to your desired result. To match with overlaps (eg 2 2 2 results in ((2 2) (2 2)) use :ov:
say #s .Str .match( / (.) ' ' $0 /, :ov ) .map: { .[0].Str xx 2 }
TIMTOWDI!
Here's an iterative approach using gather/take.
say gather for <1 1 0 2 0 2 1 2 2 2 4 4 3 3> {
state $last = '';
take ($last, $_) if $last == $_;
$last = $_;
};
# ((1 1) (2 2) (2 2) (4 4) (3 3))
In SAS Proc SQL, I am using this Case statement to try to mark policies that have differences other than .015 per year:
CASE WHEN (MOD1 - MOD0) NOT = .015 THEN 2
WHEN (MOD2 - MOD1) NOT = .015 THEN 3
WHEN (MOD3 - MOD2) NOT = .015 THEN 4
WHEN (MOD4 - MOD3) NOT = .015 THEN 5
ELSE 0 END
The weird thing is it doesn't work when it feels like it should. ( e.g. mod1 = .955 and mod0 = .94 but the first statement believes its not .015) At first I believed it to be an issue with digits but that never worked.
Oddly enough this does work and I don't know why.
CASE WHEN (MOD1 - MOD0) NOT = (1- .985) THEN 2
WHEN (MOD2 - MOD1) NOT = (1- .985) THEN 3
WHEN (MOD3 - MOD2) NOT = (1- .985) THEN 4
WHEN (MOD4 - MOD3) NOT = (1- .985) THEN 5
ELSE 0 END
But this doesn't work
CASE WHEN (MOD1 - MOD0) NOT = (.2- .185) THEN 2
WHEN (MOD2 - MOD1) NOT = (.2- .185) THEN 3
WHEN (MOD3 - MOD2) NOT = (.2- .185) THEN 4
WHEN (MOD4 - MOD3) NOT = (.2- .185) THEN 5
ELSE 0 END
I have workarounds to get around any of these (including using data steps) so I'm not really looking for solutions to the issue but more answers as to what is going on here. I like to understand why things don't work rather than just knowing what I can and can't do.
Thanks!
The problem is probably floating point arithmetic. Exact comparisons to floats is troublesome. Try something like this:
CASE WHEN ABS((MOD1 - MOD0) - 0.015) > 0.00001 THEN 2
WHEN ABS((MOD2 - MOD1) - 0.015) > 0.00001 THEN 3
WHEN ABS((MOD3 - MOD2) - 0.015) > 0.00001 THEN 4
WHEN ABS((MOD4 - MOD3) - 0.015) > 0.00001 THEN 5
ELSE 0
END
The 0.00001 is arbitrary. It is just some small number.
You can use round function:
CASE WHEN round(MOD1 - MOD0,.0001) NOT = .015 THEN 2
WHEN round(MOD2- MOD1,.0001) NOT = .015 THEN 3
WHEN round(MOD3 - MOD2,.0001) NOT = .015 THEN 4
WHEN round(MOD4 - MOD3,.0001) NOT = .015 THEN 5
ELSE 0 END
I need to run all the end cases on my function , and they all must return true (meaning the test was passed). Now in boolean I know I can use not, as a negative on a false result and it should return true.
I'm having some trouble, running the same way (using not) on a wrong result, in functions that return an integer, and while writing the test I provide the wrong answer that the list should return and it's not working, can someone please help me, thanks!
Here's an example:
(test(not((sums '(1 2 3 5 3 3) '3 0)=> 2)))
While the test that will give me a passed test will be:
(test(sums '(1 2 3 5 3 3) '3 0)=> 3))
In this example the answer is the number of 3s in the list.
Assuming that the sums function returns 3 for the given parameters, a "normal" (positive) test would look like this:
(test (sums '(1 2 3 5 3 3) 3 0) ; actual value
3) ; expected result
Now for the "negative" test you can use (not (= ... ...)) to check that the result is not a certain value, for example (added indentation for clarity):
(test (not (= (sums '(1 2 3 5 3 3) 3 0) ; actual value
2)) ; the "wrong" answer
#t) ; expected result
I'd like to display a string without the last 2 chars in a text field in Reporting Services 2005 vs2005.
I tried several ways and if the string is empty or null I get an error:
rsRuntimeErrorInExpression - The value expression for the textbox contains an error: Argument 'Length' must be greater or equal to zero.
Here are the ways I tried:
IIF(trim(Fields!kuku.Value) = "","", Left(Fields!kuku.Value, Len(Fields!kuku.Value) - 2))
IIF(IsNothing(Fields!kuku.Value) and Len(Fields!kuku.Value) = 0,"",Left(Fields!kuku.Value, Len(Fields!kuku.Value) - 2))
IIF(IsNothing(Fields!kuku.Value) ,"",Left(Fields!kuku.Value, Len(Fields!kuku.Value) - 2))
IIF(Len(Fields!kuku.Value) = 0,"",Left(Fields!kuku.Value, Len(Fields!kuku.Value) - 2))
Any ideas as to what I'm doing wrong? Thanks in advance.
how about changing the dataset on that field to use isnull(field,", ") that way you can always safely trim 2 characters.
or
IIF(IsNothing(Fields!kuku.Value) OR Len(Fields!kuku.Value) < 2,"",Left(Fields!kuku.Value, Len(Fields!kuku.Value) - 2))
note the and changed to an OR. And just in case the length is 1 changed =0 to <2