I want to selectively modify some members of a list but not all depending on whether the members satisfy some condition. For instance, in a list of values I want to subtract 9 from all values that are greater than 9.
I tried
set nodeext2 map nodeext2 [ifelse-value (? > 9) [? - 9][?]]
But get an 'expected a constant'-error. I have also tried if-else and playing around with brackets. Can anyone help me? I feel as if this is probably clearly stated somewhere but I haven't been able find where.
You simply inverted the order of the map arguments: the reporter must come before the list. Try:
set nodeext2 map [ifelse-value (? > 9) [? - 9][?]] nodeext2
You were getting the "Expected a constant" message on ifelse-value because the compiler expected the second argument of map to be a list and were thus trying to interpret [ifelse-value (? > 9) [? - 9][?]] as one (and failing because lists are made of constants, which ifelse-value is not).
Related
I am trying to understand the following SAS code snippet:
SUM( (list=.)*. , (list=.B)*. , (list=.D)*. , (list=.Q)*. )
where list contains several elements. My understanding so far is that SUM will create a new list as an output of the same length as list, summing the respective elements in the four entries. I guess list=. or list=.B etc maps the elements of list to 1 where the equality is satisfied and to 0 where it is not, but what does it mean for an element to be equal to a dot .? And what kind of quantity can .B be? Also, what does it mean to multiply by a dot, as in variable * .?
EDIT:
Upon further investigation I found out that "." stands for a NaN numeric value in SAS, so I guess list=. produces a new list where all NaN elements in list are set to 1, and all regular numbers are set to 0. But what does it mean to then multiply the resulting new list by .? And what could .B be?
What you posted kind of looks like SAS code, but not sensible SAS code.
SUM(...) in that code is a function call. The function that can take one or more arguments.
= in that code is the equality comparison operator.
* in the code is the multiplication operator.
. and .B and .D and .Q are missing values. The first is the normal missing values and the other three are examples of the other 27 special missing values that SAS supports.
Normal arithmetic, such as X+Y or A*B, will produce a missing result if any of the arguments are missing. But the SUM(,) function ignores the missing values. So the result is only missing if all of the arguments are missing.
The result of a boolean expression, such as LIST=.D , is either 1 (TRUE) or 0 (FALSE). Note that SAS only uses actual Boolean logic, it does not use the Tri-level logic that some other languages use. So X=. is true when the value of X is missing and false when it is not missing (including any of the 27 special missing values).
So far the code begins to look like an attempt to test if LIST is any of those missing values. So something like:
SUM( (list=.) , (list=.B) , (list=.D) , (list=.Q) )
This will be 1 when LIST is any of those four values. And 0 when none of the test is true.
So it is the same test as using the IN operator. Like this
list in (. .B .D .Q)
But by adding the multiplication by a missing value is what makes it nonsense. Because that will always result in a missing result. So you could just replaced the whole SUM() function call with a period to indicate you wanted a missing value no matter what value LIST had.
If you substitute actual numbers for those missing multiplicand values.
SUM( (list=.)*1 , (list=.B)*2 , (list=.D)*3 , (list=.Q)*4 )
Then perhaps it might make some sense. Now the result is a value that is coded 1 when LIST is missing and 2 when LIST is special missing .B, 3 when .D, 4 when .Q and zero otherwise.
I've been given the following exercise (one out of several that link together to pretty print a table and make selections in it):
Write a function select :: Field → Field → Table → Table that given a column name and a field value, selects only those rows from the table that have the given field value in the given column. If the given column is not present in the table then the table should be returned unchanged. (Hint: use the functions (!!), elemIndex, filter and maybe.)
And ended up with this solution:
select :: Field -> Field -> Table -> Table
select column value table#(header:rows) =
let i = fromMaybe (-1) (elemIndex column header)
in if i == (-1) then table
else header : filter (\r -> r !! i == value) rows
While it seems to be perfectly correct in its function - it works - I've been told that if-then-else constructions such as these are 'bad form' and should be avoided using guards (as should my use of fromMaybe using pattern matching).
How would I go about changing this into a 'better' style with pattern matching/guards?
One simple improvement that I immediately see when looking at your code is that it seems pointless to use fromMaybe to convert Nothing to -1, then simply do a check (whether with an if or with guards doesn't matter) on whether that value is -1. Why not check against Nothing in the first place?
I guess you might have been led this way by similar functions in other languages where if an index isn't found then -1 is returned as an artifical value (sometimes called a "sentinel value") to mean "the element wasn't found" - but in Haskell, Nothing communicates this much better.
Further Nothing can be pattern matched on, so rather than using if or guards, you can use a case statement. This turns your function into:
select :: Field -> Field -> Table -> Table
select column value table#(header:rows) =
case elemIndex column header of
Nothing -> table
Just i -> header : filter (\r -> r !! i == value) rows
This to my mind is much better than your original.
I still feel it could be improved further - in particular (!!) is rarely used in idiomatic Haskell code as it risks crashing if the index is out of bounds. It's also quite inefficient compared to the array-indexing operators of other languages (because Haskell lists are linked-lists, not arrays, and to get say the 100th element it has to run through the previous 99 rather than being able to do direct "random access"). However I don't see how you can really avoid that given what you have to work with here.
Replace
let i = fromMaybe (-1) (elemIndex column header)
in if i == (-1) then ... else ...
with
case elemIndex column header of
Nothing -> ... -- no index found
Just i -> ... -- index i found
Your original code suffers from "boolean blindness": you already have a useful value of type Maybe Int which tells you:
if there is no index (Nothing)
if there is an index, and what it is (Just i)
The last emphasized part is important! In your code you work hard to lose that information, reducing everything to a boolean telling you only:
if there is no index (True)
if there is an index, and nothing else (False)
Don't use booleans unless you really have to. Many languages must use if someBooleanCondition to conditionally branch. Haskell does not have to: we have case and pattern matching that combines branching and extracting information from each case (the i above).
I have been looking for a solution to this for quite a few hours, but unfortunately I appear to be stuck. I am trying to automatically input data based on another sheet with three possible options. DEADLINE, PMC or FMC, but it keeps crashing with if it can't find the first result. It will say #N/A, and tells me it can't find the first value. Why doesn't it check for the other values?
=IFS((MATCH(J8,Faults!F3:F9,0)),"DEADLINE",(MATCH(J6,Faults!F3:F9,0)),"PMC",(MATCH(J4,Faults!F3:F9,0)),"FMC")
Thanks in advance
MATCH does not return TRUE or FALSE. It either returns a number (the position within the range) or a #N/A error.
IFS will throw an error and stop processing just as a nested IF will. Wrap all the match functions in ISNUMBER to bypass thrown #N/A errors on no match.
=IFS(isnumber(MATCH(J8, Faults!F3:F9, 0)),"DEADLINE", isnumber(MATCH(J6, Faults!F3:F9, 0)), "PMC", isnumber(MATCH(J4, Faults!F3:F9, 0)), "FMC", true, "other")
I've added a default of Other if none of the three matches are found.
I have recently been started to play around with Redis (and am extremely pleased with all the functions it has to offer).
In particular, I was looking for a way to find all elements within a set for which a regex matches.
For example:
>>smember WORDS
1) "person"
2) "saint church"
3) "saint house"
If I wanted to return only the elements where "saint" is present, how would I do so?
I have tried to use sscan as follows:
sscan WORDS match *saint*
for which I get an error.
My understanding was that sscan can return "array of elements is a list of Set members"
Please help! Thanks!
Assuming that you have no more than 1000 elements matching you can use
sscan WORDS 0 match *saint* count 1000
If you want know the exact numbers of the elements in the set you can use SMEMBERS command.
If you want know the exact numbers of the elements in the set that MATCH with your regex, in a single command no a specific command.
Just add a ZERO as the cursor parameter for the SCAN:
sscan WORDS 0 match *saint*
I am having trouble with Erlang converting listed numbers to characters whenever none of the listed items could not also be representing a character.
I am writing a function to separate all the numbers in a positive integer and put them in a list, for example: digitize(123) should return [1,2,3] and so on.
The following code works fine, except when the list only consist of 8's and/or 9's:
digitize(_N) when _N =:= 0 -> [];
digitize(_N) when _N > 0 -> _H = [_N rem 10], _T = digitize(_N div 10), _T ++ _H.
For example: Instead of digitize(8) returning [8], it gives me the nongraphic character "\b" and digitize(89) returns "\b\t". This is only for numbers 8 and 9 and when they're put alone inside the list. digitize(891) will correctly return [8,9,1] for example.
I am aware of the reason for this but how can I solve it without altering my result? (ex: to contain empty lists inside the result like [[],[8]] for digitize(8)).
If you look at comments you will see that it is more problem of the way shell prints your data, than the data itself. You logic is wright and I would not change it. You could introduce some use of io:format/2 into you code, but I guess that it would make it harder to use this function in other parts of code.
Other way around it is changing the shell settings itself. There is shell:strings/1 functions that disables printing lists as stings, and it should do exactly what you want. Just remember to change it back when you finish with your shell stuff, since it could introduce some confusion when you will start using some "string" returning functions.