In Elixir, you can do the following:
iex> [1,2,3,4] -- [2,3]
[1,4]
Is there an analagous function for Stream types?
Trying to implement this, I have:
def stream_subtract(enum, []), do: Enum.to_list(enum)
def stream_subtract(enum1, enum2) do
head = Stream.take(enum2, 1)
new_enum1 = Stream.drop_while(enum1, &([&1] == head))
stream_subtract(new_enum1, Stream.drop(enum2, 1))
end
however this fails, as [&1] is a list, not a stream.
You will need to collect the second stream ahead of time so that you can test whether an element is present in it. Here's how you'd collect it into a MapSet and then filter the first stream using it.
Also, Stream.drop_while will only drop from the start of a stream. You need to use Stream.reject if you want to drop from arbitrary positions.
# Our two streams
foo = 1..10 |> Stream.take(4)
bar = 1..10 |> Stream.drop(1) |> Stream.take(2)
# Collect the second stream into a MapSet
bar = bar |> Enum.into(MapSet.new)
# Filter the first stream and print all items:
foo = foo |> Stream.reject(fn x -> x in bar end)
for f <- foo, do: IO.inspect(f)
Output:
1
4
Related
Currently I have a function to return the first elements of each list (floats), within a list to a separate list.
let firstElements list =
match list with
| head::_ -> head
| [] -> 0.00
My question is, how do I expand this to return elements at the same index into different lists while I don't know how long this list is? For example
let biglist = [[1;2;3];[4;5;6];[7;8;9]]
If I did not know the length of this list, what is the most efficient and safest way to get
[[1;4;7];[2;5;8];[3;6;9]]
List.transpose has been added recently to FSharp.Core
let biglist = [[1;2;3];[4;5;6];[7;8;9]]
let res = biglist |> List.transpose
//val res : int list list = [[1; 4; 7]; [2; 5; 8]; [3; 6; 9]]
You can use the recent added List.transpose function. But it is always good to be good enough to create such functions yourself. If you want to solve the problem yourself, think of a general algorithm to solve your problem. One would be.
From the first element of each list you create a new list
You drop the first element of each list
If you end with empty lists you end, otherwise repeat at step 1)
This could be the first attempt to solve the Problem. Function names are made up, at this point.
let transpose lst =
if allEmpty lst
then // Some Default value, we don't know yet
else ...
The else branch looks like following. First we want to pick the first element of every element. We imagine a function pickFirsts that do this task. So we could write pickFirsts lst. The result is a list that itself is the first element of a new list.
The new list is the result of the remaining list. First we imagine again a function that drops the first element of every sub-list dropFirsts lst. On that list we need to repeat step 1). We do that by a recursive call to transpose.
Overall we get:
let rec transpose lst =
if allEmpty lst
then // Some Default value, we don't know yet
else (pickFirsts lst) :: (transpose (dropFirsts lst))
At this point we can think of the default value. transpose needs to return a value in the case it ends up with an empty list of empty lists. As we use the result of transpose to add an element to it. The results of it must be a list. And the best default value is an empty list. So we end up with.
let rec transpose lst =
if allEmpty lst
then []
else (pickFirsts lst) :: (transpose (dropFirsts lst))
Next we need to implement the remaining functions allEmpty, pickFirsts and dropFirsts.
pickFirst is easy. We need to iterate over each element, and must return the first value. We get the first value of a list by List.head, and iterating over it and turning every element into a new list is what List.map does.
let pickFirsts lst = List.map List.head lst
dropFirsts need to iterate ver each element, and just remove the first element, or in other words keeps the remaining/tail of a list.
let dropFirsts lst = List.map List.tail lst
The remaining allEmpty is a predicate that either return true/false if we have an empty list of lists or not. With a return value of bool, we need another function that allows to return another type is a list. This is usually the reason to use List.fold. An implementation could look like this:
let allEmpty lst =
let folder acc x =
match x with
| [] -> acc
| _ -> false
List.fold folder true lst
It starts with true as the default value. As long it finds empty lists it returns the default value unchanged. As soon there is one element found, in any list, it will return false (Not Empty) as the new default value.
The whole code:
let allEmpty lst =
let folder acc x =
match x with
| [] -> acc
| _ -> false
List.fold folder true lst
let pickFirsts lst = List.map List.head lst
let dropFirsts lst = List.map List.tail lst
let rec transpose lst =
if allEmpty lst
then []
else (pickFirsts lst) :: (transpose (dropFirsts lst))
transpose [[1;2;3];[4;5;6];[7;8;9]]
Another approach would be to turn it into a 2 dimensional mutable array. Also do length checkings. Do the transformation and return the mutable array again as an immutable list.
I'm iterating through a list of strings, and I want to return the contents of a string if the beginning of it matches the provided string.
e.g.
strings = [ "GITHUB:github.com", "STACKOVERFLOW:stackoverflow.com" ]
IO.puts fn(strings, "GITHUB") // => "github.com"
This is what I thinking so far:
def get_tag_value([ << tag_name, ": ", tag_value::binary >> | rest ], tag_name), do: tag_value
def get_tag_value([ _ | rest], tag_name), do: get_tag_value(rest, tag_name)
def get_tag_value([], tag_name), do: ""
But I get this:
** (CompileError) lib/file.ex:31: a binary field without size is only allowed at the end of a binary pattern and never allowed in binary generators
Which makes sense, but then I'm not quite sure how to go about doing this. How would I match a substring to a different variable provided as an argument?
Here's how I'd do this making most use of pattern matching and no call to String.starts_with? or String.split:
defmodule A do
def find(strings, string) do
size = byte_size(string)
Enum.find_value strings, fn
<<^string::binary-size(size), ":", rest::binary>> -> rest
_ -> nil
end
end
end
strings = ["GITHUB:github.com", "STACKOVERFLOW:stackoverflow.com"]
IO.inspect A.find(strings, "GITHUB")
IO.inspect A.find(strings, "STACKOVERFLOW")
IO.inspect A.find(strings, "GIT")
IO.inspect A.find(strings, "FOO")
Output:
"github.com"
"stackoverflow.com"
nil
nil
There are many ways to skin this cat.
For example:
def get_tag_value(tag, strings) do
strings
|> Enum.find("", &String.starts_with?(&1, tag <> ":"))
|> String.split(":", parts: 2)
|> Enum.at(1, "")
end
or if you still wanted to explicitly use recursion:
def get_tag_value(_tag, []), do: ""
def get_tag_value(tag, [str | rest]) do
if String.starts_with?(str, tag <> ":") do
String.split(str, ":", parts: 2) |> Enum.at(1, "")
else
get_tag_value(tag, rest)
end
end
Are just two of many possible ways.
However, you won't be able to pattern match the string in the function head without knowing it (or at least the length) beforehand.
iex(1)> strings = [ "GITHUB:github.com", "STACKOVERFLOW:stackoverflow.com" ]
iex(2)> Enum.filter(strings, fn(s) -> String.starts_with?(s, "GITHUB") end)
iex(3)> |> Enum.map(fn(s) -> [_, part_2] = String.split(s, ":"); part_2 end)
# => ["github.com"]
In Enum.filter/2 I select all strings they start with "GITHUB" and I get a new List. Enum.map/2 iterates through the new List and splits each string at the colon to return the second part only. Result is a List with all parts after the colon, where the original string starts with "GITHUB".
Be aware, that If there's an item like "GITHUBgithub.com" without colon, you get a MatchError. To avoid this either use String.starts_with?(s, "GITHUB:") to filter the right strings or avoid the pattern matching like I did in Enum.map/2 or use pattern matching for an empty list like #ryanwinchester did it.
You can use a combination of Enum.map and Enum.filter to get the matching pairs you're looking for:
def get_tag_value(tag_name, tags) do
tags
|> Enum.map(&String.split(&1, ":")) # Creates a list of [tag_name, tag_value] elements
|> Enum.filter(fn([tn, tv]) -> tn == tag_name end) # Filters for the tag name you're after
|> List.last # Potentially gets you the pair [tag_name, tag_value] OR empty list
end
And in the end you can either call List.last/1 again to either get an empty list (no match found) or the tag value.
Alternatively you can use a case statement to return a different kind of result, like a :nomatch atom:
def get_tag_value(tag_name, tags) do
matches = tags
|> Enum.map(&String.split(&1, ":")) # Creates a list of [tag_name, tag_value] elements
|> Enum.filter(fn([tn, tv]) -> tn == tag_name end) # Filters for the tag name you're after
|> List.last # Potentially gets you the pair [tag_name, tag_value] OR empty list
case matches do
[] -> :nomatch
[_, tag_value] -> tag_value
end
end
This would be my take in Erlang:
get_tag_value(Tag, Strings) ->
L = size(Tag),
[First | _] = [Val || <<Tag:L/binary, $:, Val/binary>> <- Strings]
First.
The same in Elixir (there are probably more idiomatic ways of writing it, tho):
def gtv(tag, strings) do
l = :erlang.size(tag)
[first | _ ] =
for << t :: binary - size(l), ":", value :: binary >> <- strings,
t == tag,
do: value
first
end
I have some records with similar fields, like this:
-define(COMMON_FIELDS, common1, common2, common3).
-record(item1, a, b, c, ?COMMON_FIELDS).
-record(item2, x, y, z, ?COMMON_FIELDS).
But later I need to write similar code for every record:
Record#item1.common1,
Record#item1.common2,
Record#item1.common3
and:
Record#item2.common1,
Record#item2.common2,
Record#item2.common3
Is there way to write one function for access to same fields in different records?
Is there way to write one function for access to same fields in
different records?
1) Pattern matching in multiple function clauses:
-module(x1).
-export([read/1]).
-define(COMMON_FIELDS, common1, common2, common3).
-record(item1, {x, ?COMMON_FIELDS}). %Note that you defined your records incorrectly.
-record(item2, {y, ?COMMON_FIELDS}).
read(#item1{common1=C1, common2=C2, common3=C3} = _Item) ->
io:format("~p, ~p, ~p~n", [C1, C2, C3]);
read(#item2{common1=C1, common2=C2, common3=C3} = _Item) ->
io:format("~p, ~p, ~p~n", [C1, C2, C3]).
...
25> c(x1).
{ok,x1}
26> rr(x1).
[item1,item2]
27> A = #item1{x=10, common1="hello", common2="world", common3="goodbye"}.
#item1{x = 10,common1 = "hello",common2 = "world",
common3 = "goodbye"}
28> B = #item2{y=20, common1="goodbye", common2="mars", common3="hello"}.
#item2{y = 20,common1 = "goodbye",common2 = "mars",
common3 = "hello"}
29> x1:read(A).
"hello", "world", "goodbye"
ok
30> x1:read(B).
"goodbye", "mars", "hello"
ok
Note the export statement--it's a list of length 1, i.e. the module exports one function. The output shows that the read() function can read records of either type.
2) A case statement:
If for some reason, by stating one function you mean one function clause, you can do this:
read(Item) ->
case Item of
#item1{common1=C1, common2=C2, common3=C3} -> true;
#item2{common1=C1, common2=C2, common3=C3} -> true
end,
io:format("~p, ~p, ~p~n", [C1, C2, C3]).
You can use exprecs parse transform from parse_transe.
-module(parse).
-compile({parse_transform, exprecs}).
-record(item1, {x, common1, common2}).
-record(item2, {y, common1, common2}).
-export_records([item1, item2]).
-export([p/0]).
f() ->
R1 = #item1{x=1, common1=foo1, common2=bar1},
R2 = #item2{y=2, common1=foo2, common2=bar2},
['#get-'(Field, Rec) || Field <- [common1, common2], Rec <- [R1, R2]].
...
1> c(parse).
{ok,parse}
2> parse:f().
[foo1,foo2,bar1,bar2]
It might make sense to factor out the common fields into a single field in each record companies containing a record with all the common data or even a tulple. Then refactor your code to do all common processing to its own function.
You still need to pattern match every top level record to get the common sub record. But somewhere you probably want to do the processing specific to each record kind and there you can already match out the common field.
-record(common, {c1, c2, c3}).
-record(item1, {a, b, c, com}).
...
process_item(#item1{a=A, b=B, c=C, com=Com}) ->
process_abc(A, B, C),
process_common(Com),
...;
process_item(#item2{x=X, y=Y ...
Data structures like this might also be a indication to use the new Map data type instead of records.
I have a list of tuples like so:
let scorecard = [ for i in 0 .. 39 -> i,0 ]
I want to identify the nth tuple in it. I was thinking about it in this way:
let foundTuple = scorecard |> Seq.find(fun (x,y) -> x = 10)
I then want to create a new tuple based on the found one:
let newTuple = (fst foundTuple, snd foundTuple + 1)
And have a new list with that updated value
Does anyone have some code that matches this pattern? I think I have to split the list into 2 sublists: 1 list has 1 element (the tuple I want to replace) and the other list has the remaining elements. I then create a new list with the replacing tuple and the list of unchanged tuples...
You can use List.mapi which creates a new list using a specified projection function - but it also calls the projection function with the current index and so you can decide what to do based on this index.
For example, to increment second element of a list of integers, you can do:
let oldList = [0;0;0;0]
let newList = oldList |> List.mapi (fun index v -> if index = 1 then v + 1 else v)
Depending on the problem, it might make sense to use the Map type instead of list - map represents a mapping from keys to values and does not need to copy the entire contents when you change just a single value. So, for example:
// Map keys from 0 to 3 to values 0
let m = Map.ofList [0,0;1,0;2,0;3,0]
// Set the value at index 1 to 10 and get a new map
Map.add 1 10 m
I went back and thought about the problem and decided to use an array, which is mutable.
let scorecard = [| for i in 0 .. 39 -> i,0 |]
Since tuples are not mutable, I need to create a new tuple based on the existing one and overwrite it in the array:
let targetTuple = scorecard.[3]
let newTuple = (fst targetTuple, snd targetTuple + 1)
scorecard.[3] <- newTuple
I am using the "<-" which is a code smell in F#. I wonder if there a comparable purely functional equivalent?
I have a function which returns a sequence of records. In that function I start the list building with a blank dummy record (there is probably a better way to do it) because I need to accumulate records that are similar, so I "prime the pump" with a blank record. Here's my code:
let consolidate(somethings:seq<Something>) =
let mutable results = ResizeArray()
let mutable accumulatedSomething = {Foo = ""; Bar = ""; Count = 0;}
for s in somethings do
if s.Foo = accumulatedSomething.Foo && s.Bar = accumulatedSomething.Bar then
accumulatedSomething <- {Foo = s.Foo; Bar = s.Bar;
Count = s.Count + accumulatedSomething.Count}
else
results.Add(accumulatedSomething)
accumulatedSomething <- e
results |> Seq.cast |> Seq.skip 1
If you have a way to make this better I'm all ears (I'm still thinking procedurally) but I'm still interested in an answer to this specific question. Later on in my code, I try to print out the list:
somethings |> Seq.iter( fun s -> printfn "%A" s)
This works fine when there is stuff in the list. But if the list is empty and the only record that was in the list was the skipped blank starter record, then this line fails with an InvalidOperationException with the message The input sequence has an insufficient number of elements?
Why does this happen and how can I fix it?
The problem occurs when somethings is an empty list.
In this case, results is empty and calling Seq.skip 1 on the empty list fails with an error.
I think an elegant solution would be to change the last line to
match results.Length with
| 0 -> results |> Seq.cast
| _ -> results |> Seq.cast |> Seq.skip 1