def create(conn, params) do
conn
|> render_json_response(bulk_convertor(params))
end
def bulk_convertor(%{"file" => %Plug.Upload{content_type: "text/csv", filename: basename,
path: fullpath}}) do
list = [~w(old, new)]
fullpath
|> read_csv(list)
|> form_response
end
def read_csv(path, list) do
if path |> File.stream! |> Enum.count <= 50 do
path
|> File.stream!
|> Parser.parse_stream
|> Stream.map(fn [arg] -> %{url: arg} end)
|> iterate_urls(list)
else
%{error: %{message: "Limit Exceeded"}}
end
end
def iterate_urls(mapped_stream, list) do
mapped_stream
|> Enum.each(fn(url) -> url_convertor(url, list) end)
%{response: %{message: "Request Initiated"}}
end
def url_convertor(%{url: val}, list) do
with {:ok, %Route{} = route} <- App.create_route(%{"url" => val}) do
route
|> App.redirect_url
|> add_to_list(route, list)
end
end
def add_to_list(new_url, %{url: original_url}, list) do
list = List.insert_at(list, -1, ~w(#{original_url}, #{new_url}))
list
end
The list content is not updated whenever I try to print it somewhere using IO.inspect it shows the initial list.
I am trying to update the content of the list based on the data parsed from the csv which i am parsing using the nimble_csv library of elixir.
If I try to print the list inside
add_to_list
only two rows are visible the header that i added initially and last row from the CSV.
Is there anything I am doing wrong here.
You create a new list in add_to_list function, the function returns the new list but you ignore it. Data structures are immutable in Elixir. Check out this answer: elixir not updating values in mapset using enum.each
As I came to know that the DS in elixir is immutable I am able to solve the above problem by making a minor change in the function below
def iterate_urls(mapped_stream) do
mapped_stream
|> Enum.flat_map(fn(url) -> url_convertor(url) end)
|> dump_to_csv
%{response: %{message: "Request Initiated"}}
end
The rest remains the same now this line
Enum.flat_map(fn(url) -> url_convertor(url) end)
return list I wanted.
Related
I have simple list that contains inside list
let ftss = [
["a","aData"],["b","bData"]
]
I want to iterate and access the elements "a" and "aData" etc.
I tried
List.iter (fun item ->
for i in 0..1 do
printfn "%s" item[i])
how do i access the elements inside the internal list?
Thanks
So, 1st thing is a comma isnt a delimter in a list, but in a tuple ',' so
let ftss = [
["a","aData"],["b","bData"]
]
is actually of type
val ftss: ((string * string) list * (string * string) list) list =
i.e. its a list of 1 entry of a tuple of a list of 1 entry each of a tuple.
which I THINK isnt what you intended?
I THINK you want (a ';' or new line delimits each entry)
let ftss3 = [
["a";"aData"]
["b";"bData"]
]
which is
val ftss3: string list list = [["a"; "aData"]; ["b"; "bData"]]
i.e. a list of a list of strings.
(I'd try to use FSI to enter these things in, and see what the types are)
so to iterate this list of lists you would go
List.iter (fun xs ->
List.iter (fun x ->
printfn "%s" x)
xs)
ftss3
As pointed out in the existing answer, you probably want to represent your data as a list of lists, for which you need to use the ; delimiter (to make a list) rather than , to construct a singleton containing a tuple.
I would just add that if you want to perform an imperative action with each of the items, such as printing, then it is perfectly reasonable to use an ordinary for loop:
let ftss = [
["a"; "aData"]; ["b"; "bData"]
]
for nested in ftss do
for item in nested do
printfn "%s" item
I have a source list that looks like:
let source = ["A", "B", "%", "C", "Y", "%"]
I want to go through each element and each time I hit the token "%", every element of the preceding list should go into a sub list. The result should look like this.
let result = [["A", "B"], ["C", "Y"]]
I think I have to use the fold function of list, but my result type is string list instead of string list list
let folder (acc, current) item =
match item with
| "" -> (current # acc, [])
| _ -> (acc, current # [item])
let result = source
|> List.fold folder ([], [])
|> fun (a,_) -> a
Any ideas?
You were very close, but I think one issue was your source list was actually a list with one big tuple in it. You have to separate list items with ;. Comma , is used to separate items in a tuple.
let source = ["A"; "B"; "%"; "C"; "Y"; "%"]
Then with some minor changes to your folder function:
let folder (acc, current) item =
match item with
| "%" -> (acc # [current], [])
| _ -> (acc, current # [item])
You now get the result you want:
let result =
source
|> List.fold folder ([], [])
|> fst
> val result : string list list = [["A"; "B"]; ["C"; "Y"]]
This is not as generic but you can take advantage of string operations to do this more succinctly.
(String.concat "" source).Split([|'%'|], StringSplitOptions.RemoveEmptyEntries)
|> List.ofArray
|> List.map List.ofSeq
Assumes Taylor's fix to source to make it a proper list.
Consider a (smelly, non-idiomatic) function like the below:
def update_2d(array, inds, val) do
[first_coord, second_coord] = inds
new_arr = List.update_at(array, second_coord, fn(y) ->
List.update_at(Enum.at(array, second_coord),
first_coord, fn(x) -> val end) end)
end
This function will take in a list of lists, a list of two indices, and a value to insert within the list of lists at the location specified by the indices.
As a first step to making this more Elixir-ey, I start laying pipe:
array
|> Enum.at(second_coord)
|> List.update_at(first_coord, fn(x) -> val end)
That gets me most of the way there, but how do I pipe that output into the anonymous function of the last List.update_at call? I can nest it within the original call, but that seems like giving up:
List.update_at(array, second_coord, fn(y) ->
array
|> Enum.at(second_coord)
|> List.update_at(first_coord, fn(x) -> val end)
end)
You can simply bind to a variable to capture your first result and then replace it in the second List.update_at/3 call
def update_2d(array, inds = [first_coord, second_coord], val) do
updated =
array
|> Enum.at(second_coord)
|> List.update_at(first_coord, fn(x) -> val end)
List.update_at(array, second_coord, fn(x) -> updated end)
end
You can also use the capture operator to do this:
def update_2d(array, inds = [first_coord, second_coord], val), do:
array
|> Enum.at(second_coord)
|> List.update_at(first_coord, fn(x) -> val end)
|> (&(List.update_at(array, second_coord, fn(y) -> &1 end))).()
I find using a variable much more readable, but the option is there.
How about:
{:foo, :bar} |> elem(1) |> Enum.Map(fn x -> x end)
Seems easier.
I need to sort a list that is type
ListToSort val: (string*Seq<string>) list
My idea is to sort this list by the length of the sequence
Im using the commands List.Sortby snd and Seq.Length but I havent been able to make it work..
Any ideas?
thanks
EDIT:
A more Clear idea of the code is (the list that I want to sort is created by Seq.grouby that groups repeated elements in the original list)
let grouped =
OriginalList
|> Seq.groupBy (fun value -> if value = value then value else "else" )
|> Seq.toList
|> Seq.Sortby.... // sort the list by the length of the sequence
Adding the line
|> List.sortBy(fun (_, s) -> Seq.length s) –
Suggusted by vcsjones made it work
let grouped =
OriginalList
|> Seq.groupBy (fun value -> if value = value then value else "else" )
|> Seq.toList
|> List.sortBy(fun (_, s) -> Seq.length s) –
This returned the list sorted!!
type Dictionary = [(String, String)]
dict :: Dictionary
dict = ("Deutsch", "English"):[]
insert :: Dictionary -> (String,String) -> Dictionary
insert dict entry = dict ++ [entry]
One thing that I didn't find about the way lists work: Is it somehow possible to overwrite the existing dict with the entry added in insert? Or is it necessary to, in the next step, always write out the list that was put out by insert?
insert [("German", "English"), ("Hallo", "hello")] ("Versuch", "try")
So far, this is the only way I have been able to add something to the new list without losing the previous entry. However, next on the list of things to implement is a search command, so I wonder if I'd also have to write this out in the search function.
The idea of functional programming is in general that your data is immutable. This means once you have created a list, you can NEVER change that list. But you can copy that list, make modifications to it, and keep that as well.
So when you have a list like so
test = [1,2,3]
We can modify this by adding 4 to the start:
test2 = 4 : test
: called the cons operator, puts an element in front of a list. Do note that x:xs (the same as doing [x]++xs) has a better performance than doing xs++[x]
So now we have two bindings, one of test to [1,2,3] and one of test2 to [4,1,2,3]
Hope this clarifies things
To give a full example:
type Dictionary = [(String, String)]
insert :: Dictionary -> (String,String) -> Dictionary
insert dict entry = dict ++ [entry]
dict0 = [ ("Deutsch", "English") ]
dict1 = insert dict0 ("Hallo", "hello")
dict2 = insert dict1 ("Versuch", "try")
If you're new to functional programming, I would recommend reading Learn You a Haskell for Great Good , which is a fantastic (and free) book on how to use Haskell -- and functional programming in general.
It's not too tough to do this
import Data.List (lookup)
insert :: Eq a => (a,b) -> [(a,b)] -> [(a,b)]
insert (a,b) [] = [(a,b)]
insert (a,b) ((c,d):rest) = if a == c
then (a,b) : rest
else (c,d) : insert (a,b) rest
---
dict :: [(String, String)]
dict = [("Deutsch", "English")]
If you can't use Data.List then you can define lookup by
lookup :: Eq a => a -> [(a,b)] -> Maybe b
lookup _ [] = Nothing
lookup k ((a,b):rest) = if k == a then Just b else lookup k rest
Now if you load up GHCI:
>> let dict' = insert ("Ein","One") dict
>> dict'
[("Deutsch","English"),("Ein","One")]
>> lookup "Ein" dict'
Just "One"
>> insert ("Deutsch", "Francais") dict'
[("Deutsch","Francais"),("Ein","One")]
If you want to replace an existing pair with the same key then you could write insert as:
insert :: Dictionary -> (String, String) -> Dictionary
insert [] p = [p]
insert ((dk, dv):ps) p#(k, v) | dk == k = p:ps
insert (p:ps) ip = p : (insert ps ip)
However if you are writing an association list, then you can simplify it by inserting new items at the front of the list:
insert :: Dictionary -> (String, String) -> Dictionary
insert = flip (:)
if you then search from the front of the list, it will find any values added more recently first.
In Haskell, most values are immutable, meaning that you can not change their value. This seems like a huge constraint at first, but in reality it makes it easier to reason about your program, especially when using multiple threads.
What you can do instead is continually call insert on the dictionary returned when you call insert, for example:
mainLoop :: Dictionary -> IO ()
mainLoop dict = do
putStrLn "Enter the German word:"
german <- getLine
putStrLn "Enter the English word:
english <- getLine
let newDict = insert dict (german, english)
putStrLn "Continue? (y/n)"
yesno <- getChar
if yesno == 'y'
then mainLoop newDict
else print newDict
main = do
One simply can't 'overwrite' anything in a pure language (outside of ST monad). If I understood your question correctly, you are looking for something like this:
insert :: Dictionary -> (String,String) -> Dictionary
insert [] b = [b] -- If this point is reached where wasn't matching key in dictionary, so we just insert a new pair
insert (h#(k, v) : t) b#(k', v')
| k == k' = (k, v') : t -- We found a matching pair, so we 'update' its value
| otherwise = h : insert t b