Elixir binary search - if-statement

I built a binary search in Elixir but I ended up using 3 if clauses:
if actual == guessed_number, do:
if actual > guessed_number do:
if actual < guessed_number do:
Is it possible to not use conditionals at all? Maybe with Pattern Matching?

DISCLAIMER: do not use this in production, this is slower than a simple linear search because linked lists do not allow for random access in constant time. This post is merely about the pattern matching aspect.
Theoretically you can use guard clauses, but they can make things much worse if you overdo it. Assuming you start with an implementation like this:
defmodule MyEnum do
def binsearch(collection, key) do
binsearch(collection, key, 1, length(collection))
end
defp binsearch(collection, key, lo, hi) do
if hi < lo do
-1
else
mid = div(lo + hi, 2)
item = Enum.at(collection, mid)
cond do
key < item -> binsearch(collection, key, lo, mid-1)
key > item -> binsearch(collection, key, mid+1, hi)
true -> mid
end
end
end
end
Maybe you want to extract the if into a guard clause:
defmodule MyEnum do
def binsearch(collection, key) do
binsearch(collection, key, 1, length(collection))
end
defp binsearch(_collection, _key, lo, hi) when hi < lo do
-1
end
defp binsearch(collection, key, lo, hi) do
mid = div(lo + hi, 2)
item = Enum.at(collection, mid)
cond do
key < item -> binsearch(collection, key, lo, mid-1)
key > item -> binsearch(collection, key, mid+1, hi)
true -> mid
end
end
end
Now you could also pull the cond out into guard clauses but it's not really an improvement:
defmodule MyEnum do
def binsearch(collection, key) do
binsearch(collection, key, 1, length(collection))
end
defp binsearch(_collection, _key, low, hi) when hi < low do
-1
end
defp binsearch(collection, key, low, hi) do
mid = div(low + hi, 2)
item = Enum.at(collection, mid)
binsearch(collection, key, item, low, mid, hi)
end
defp binsearch(collection, key, item, low, mid, _hi) when key < item do
binsearch(collection, key, low, mid-1)
end
defp binsearch(collection, key, item, _low, mid, hi) when key > item do
binsearch(collection, key, mid+1, hi)
end
defp binsearch(_collection, _key, _item, _low, mid, _hi) do
mid
end
end

You cannot do this with pattern matching. However, you can use cond which is like Erlang's if:
cond do
actual == guessed_number ->
...
actual > guessed_number ->
...
actual < guessed_number ->
...
end

Related

Delete the ith element of a list

Write a function that deletes the ith element of a list. If the length of the list is less than i, return the list.
This is the output wanted:
- deleteIth([1,2,3,4,5,6],3);
val it = [1,2,4,5,6] : int list
- deleteIth([1,2,3,4,5,6],7);
val it = [1,2,3,4,5,6] : int list
Here's my code:
fun deleteIth (L, i) =
let
(* Deletes the element of a list at ith index *)
fun delete (nil, i, position) = nil
| delete (x::xs, i, position) = if i = position then xs else
x :: delete (xs, i, position + 1)
in
if i >= 0 andalso i < length L then delete (L, i, 0) else L
end;
note: the line x :: delete (xs, I, position + 1) should be right after the else in the previous line the line wrap made me show the code this way. Sorry for that.
But my code out puts
- deleteIth([1,2,3,4,5,6],3);
val it = [1,2,3,5,6] : int list
- deleteIth([1,2,3,4,5,6],7);
val it = [1,2,3,4,5,6] : int list
I would appreciate the help thanks.
Since you've got your expected results, here's a shorter version that only traverses the list once, and never beyond the element to remove.
(length must traverse the entire list to determine its length. It's possibly the least useful list function.)
The general case, k > 1 and the list is not empty:
To remove the k:th element, remove element k-1 from the tail of the list, then add the head of the original list to the result.
Base cases:
Removing element 1 from a list produces the tail of the list.
Removing anything from the empty list produces the empty list.
The case where the list is shorter than k will terminate when it reaches the empty list.
Like this:
fun delete_ith ([], k) = []
| delete_ith (x::xs, 1) = xs
| delete_ith (x::xs, k) = x :: delete_ith (xs, k - 1)

Concurrent Sieve in Erlang

I have a code that uses the Sieve of Eratosthenes method to generate prime numbers up to a given limit N.
Method:
Split the list of odd numbers into segments
Each segment gets passed to a process
Segments are sieved concurrently with the set Lp
Here is the code:
%---------------------------------------------------------------------------------
primes(N) ->
simple_sieve(lists:seq(3,N,2),[],N).
simple_sieve(Lin,Lp,N) -> [H|_] = Lin,
case H*H < N of
true -> simple_sieve([X || X <- Lin, X rem H =/= 0], [H|Lp], N);
false -> lists:reverse(Lp) ++ Lin
end.
%---------------------------------------------------------------------------------
primes_parr(N, Num_blocks) ->
Pid_stem = self(),
SQ = round(math:sqrt(N)),
Lp = primes(SQ), io:fwrite("List of primes: ~w~n", [Lp]),
Block_size = round(N/Num_blocks),
ok = leaf_spawn(Pid_stem, Lp, SQ, Block_size, Num_blocks),
stem_loop(Lp, 0, Num_blocks).
stem_loop(Lp, Primes, 0) ->
1 + length(Lp) + Primes;
stem_loop(Lp, Primes, Num_blocks) ->
receive
{leaf_done, _, Leaf_nums} ->
stem_loop(Lp, Primes+Leaf_nums, Num_blocks-1)
end.
leaf_spawn(_, _, _, _, 0) -> ok;
leaf_spawn(Pid_stem, Lp, SQ, Block_size, Num_blocks) ->
case (Num_blocks==1) of
true -> case (SQ rem 2 == 0) of
true -> Start = SQ+1;
false -> Start = SQ
end;
false -> Start = 1
end,
First = (Num_blocks-1)*Block_size + Start,
Last = Num_blocks*Block_size,
io:fwrite("Start: ~w | Finish: ~w ~n", [First,Last]),
spawn(fun() -> leaf(Pid_stem, Num_blocks, First, Last, [], Lp) end),
leaf_spawn(Pid_stem, Lp, SQ, Block_size, Num_blocks-1).
leaf(Pid_stem, Leaf_id, First, Last, Leaf_nums, []) ->
L = ordsets:subtract(lists:seq(First,Last,2),lists:usort(Leaf_nums)),
io:fwrite("The sublist is: ~w~n", [L]),
Pid_stem ! {leaf_done, Leaf_id, length(ordsets:subtract(lists:seq(First,Last,2),lists:usort(Leaf_nums)))};
leaf(Pid_stem, Leaf_id, First, Last, Leaf_nums, [H|T]) ->
case (H*H =< Last) of
true ->
case H*H >= First of
true ->
leaf(Pid_stem, Leaf_id, First, Last, lists:seq(H*H, Last, 2*H) ++ Leaf_nums, T);
false ->
K = round((First - H*H)/(2*H)),
leaf(Pid_stem, Leaf_id, First, Last, lists:seq(H*H + 2*K*H, Last, 2*H) ++ Leaf_nums, T)
end;
false ->
leaf(Pid_stem, Leaf_id, First, Last, Leaf_nums, [])
end.
If I call the function primes_parr(100,2), the code works just fine. Giving me the output:
List of primes(Lp): [3,5,7]
Start: 51 | Finish: 100
Start: 11 | Finish: 50
The sublist is: [53,59,61,67,71,73,79,83,89,97]
The sublist is: [11,13,17,19,23,29,31,37,41,43,47]
25 %no. of primes
But if I call primes_parr(100,3), the output becomes invalid. With the output being:
List of primes(Lp): [3,5,7]
Start: 67 | Finish: 99
Start: 34 | Finish: 66
Start: 11 | Finish: 33
The sublist is: [67,71,73,79,83,89,97]
The sublist is: [34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66]
The sublist is: [11,13,17,19,23,29,31]
35 %no. of primes
I'd like to know what's causing the error if I split the list into more than two segments.
Judging by your invalid output
The sublist is: [67,71,73,79,83,89,97]
The sublist is: [34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66] %% HERE
The sublist is: [11,13,17,19,23,29,31]
somewhere your code assumes that a starting number of a range to sieve is odd.
Indeed,
leaf(Pid_stem, Leaf_id, First, Last, Leaf_nums, []) ->
L = ordsets:subtract(lists:seq(First,Last,2),lists:usort(Leaf_nums)),
io:fwrite("The sublist is: ~w~n", [L]),
Pid_stem ! {leaf_done, Leaf_id, length(L)}; %% reuse the L !!
assumes that First is odd, when it calculates lists:seq(First,Last,2).
This should be simple to fix. Just add 1 to First if it's even, immediately after you've calculated it inside leaf_spawn. (edit: better do it here, on entry into leaf, so its requirement is clearly seen and is enforced by it itself).
Also, sometimes your biggest prime in Lp is also included as the first prime in the lowest block (e.g. for N=121, N=545).

How to cycle a list infinitely and lazily in Kotlin?

I have a list of directions and want to find the next direction when I take a right or left turn. Here is the working code I have:
enum class Turn { R, L }
enum class Direction { N, E, S, W }
val directionsInRightTurnOrder = listOf(Direction.N, Direction.E, Direction.S, Direction.W)
private fun calculateNextHeading(heading: Direction, turn: Turn): Direction {
val currentIndex = directionsInRightTurnOrder.indexOf(heading)
var nextIndex = currentIndex + if (turn == Turn.R) 1 else -1
if (nextIndex >= directionsInRightTurnOrder.size)
nextIndex = directionsInRightTurnOrder.size - nextIndex
if (nextIndex < 0)
nextIndex += directionsInRightTurnOrder.size
return directionsInRightTurnOrder.get(nextIndex)
}
However, this would be so much simpler and easier to read if I could take the directionsInRightTurnOrder list and cycle through it infinitely (and lazily). In Clojure, I can do that, using clojure.core/cycle:
(take 5 (cycle ["a" "b"]))
# ("a" "b" "a" "b" "a")
Another thing that would help is if I could look up in a list using a negative index, like in Ruby or Python:
http://rubyquicktips.com/post/996814716/use-negative-array-indices
Negative index to Python list
Question:
Can I do cycle through a list/collection in Kotlin?
Is there an idiomatic way to do a negative-index-lookup in Kotlin?
Here's cycle:
fun <T : Any> cycle(vararg xs: T): Sequence<T> {
var i = 0
return generateSequence { xs[i++ % xs.size] }
}
cycle("a", "b").take(5).toList() // ["a", "b", "a", "b", "a"]
Here's how you could implement turn application:
enum class Turn(val step: Int) { L(-1), R(1) }
enum class Direction {
N, E, S, W;
fun turned(turn: Turn): Direction {
val mod: (Int, Int) -> Int = { n, d -> ((n % d) + d) % d }
return values()[mod(values().indexOf(this) + turn.step, values().size)]
}
}
Sounds like modulo is what you're looking for -- negative index wrap-around. Couldn't find it in Kotlin's stdlib so I brought my own.
Direction.N
.turned(Turn.R) // E
.turned(Turn.R) // S
.turned(Turn.R) // W
.turned(Turn.R) // N
.turned(Turn.L) // W
Enum#values() and Enum#valueOf(_) are what let you access an enum's members programmatically.
Custom sequence, which repeats indefinitely the given sequence or list can be written quite easily in terms of flatten:
fun <T> Sequence<T>.repeatIndefinitely(): Sequence<T> =
generateSequence(this) { this }.flatten()
fun <T> List<T>.repeatIndefinitely(): Sequence<T> =
this.asSequence().repeatIndefinitely()
You can cycle through a list/collection in Kotlin by generating a sequence that returns the list/collection repeatedly and then flattening it. e.g.:
generateSequence { listOf("a", "b") }.flatten().take(5).toList()
// [a, b, a, b, a]
You can define your own modulo function for coercing both negative and positive numbers to valid indices to access elements in a list (see also Google Guava's IntMath.mod(int, int)):
infix fun Int.modulo(modulus: Int): Int {
if (modulus <= 0) throw ArithmeticException("modulus $modulus must be > 0")
val remainder = this % modulus
return if (remainder >= 0) remainder else remainder + modulus
}
val list = listOf("a", "b", "c", "d")
list[-1 modulo list.size] // last element
list[-2 modulo list.size] // second to last element
list[+9 modulo list.size] // second element
list[-12 modulo list.size] // first element
Paraphrasing the discussion on kotlin Slack:
using List#modulo would make this simpler, but not as elegant as cycle still, since negative indexes will still need to be handled.
One option to implement a cyclical list is a Sequence. However, a custom Sequence will need to be written, or generated using generateSequence. We thought it's an overkill for this situation.
Eventually I went with:
Making Direction aware of next and previous:
enum class Direction {
N, E, S, W;
private val order by lazy { listOf(N, E, S, W) }
fun add(turns: Int): Direction {
val currentIndex = order.indexOf(this)
var nextIndex = (currentIndex + turns) % order.size
return order.possiblyNegativeLookup(nextIndex)
}
fun subtract(turns: Int) = add(-1 * turns)
fun next(): Direction = add(1)
fun previous(): Direction = subtract(1)
}
Extending List with possiblyNegativeLookup:
fun <E> List<E>.possiblyNegativeLookup(i: Int): E {
return if (i < 0) this[this.size + i] else this[i]
}
So the final code turns into:
val nextHeading = if (move.turn == Turn.R) heading.next() else heading.previous()

Erlang - element and list

I'm new to erlang. I wonder how to write a function which returns the first N elements in a list?
I've tried:
take([],_) -> [];
take([H|T],N) when N > 0 -> take([H,hd(L)|tl(T)], N-1);
take([H|T],N) when N == 0 -> ... (I'm stuck here...)
Any hint? thx
Update: I know there's a function called "sublist" but I need to figure out how to write that function by my own.
I finally figured out the answer:
-module(list).
-export([take/2]).
take(List,N) -> take(List,N,[]).
take([],_,[]) -> [];
take([],_,List) -> List;
take([H|T], N, List) when N > 0 -> take(T, N-1, lists:append(List,[H]));
take([H|T], N, List) when N == 0 -> List.
In Erlang, take is spelled lists:sublist:
L = [1, 2, 3, 4];
lists:sublist(L, 3). % -> [1, 2, 3]
A simple solution is:
take([H|T], N) when N > 0 ->
[H|take(T, N-1)];
take(_, 0) -> [].
This will generate an error if there are not enough elements in the list.
When you use an accumulator as you are doing you do not usually append elements to the end of it as this is very inefficient (you copy the whole list each time). You would normally push elements on to it with [H|List]. It will then be in the reverse order but you then do a lists:reverse(List) to return them in the right order.
take(List, N) -> take(List, N, []).
take([H|T], N, Acc) when N > 0 ->
take(T, N-1, [H|Acc]);
take(_, 0, Acc) -> lists:reverse(Acc).
The accumulator version is tail recursive which is a Good Thing but you need to do an extra reverse which removes some of the benefits. The first version I think is clearer. There is no clear case for either.

List is conceived as integer by length function

I'm trying to learn Erlang using the Karate Chop Kata. I translated the runit test supplied in the kata to an eunit test and coded up a small function to perform the task at hand.
-module(chop).
-export([chop/2]).
-import(lists).
-include_lib("eunit/include/eunit.hrl").
-ifdef(TEST).
chop_test_() -> [
?_assertMatch(-1, chop(3, [])),
?_assertMatch(-1, chop(3, [1])),
?_assertMatch(0, chop(1, [1])),
....several asserts deleted for brevity...
].
-endif.
chop(N,L) -> chop(N,L,0);
chop(_,[]) -> -1.
chop(_, [],_) -> -1;
chop(N, L, M) ->
MidIndex = length(L) div 2,
MidPoint = lists:nth(MidIndex,L),
{Left,Right} = lists:split(MidIndex,L),
case MidPoint of
_ when MidPoint < N -> chop(N,Right,M+MidIndex);
_ when MidPoint =:= N -> M+MidIndex;
_ when MidPoint > N -> chop(N,Left,M)
end.
Compiles ok.Running the test however gives, (amongst others) the following failure:
::error:badarg
in function erlang:length/1
called as length(1)
in call from chop:chop/3
I've tried different permutations of declaring chop(N,[L],M) .... and using length([L]) but have not been able to resolve this issue. Any suggestions are welcome.
ps. As you might have guessed I'm a nube when it comes to Erlang.
So I'm pressed for time at the moment, but the first problem I see is that
chop(N,L) -> chop(N,L,0);
chop(_,[]) -> -1.
is wrong because chop(N,L) will always match. reverse the clauses and see where that gets you.
Beyond that, in the case of the 1 element list, nth(0, [1]) will fail. I feel like these lists are probably 1-indexed.
As most significant thing to learn you should realize, that using binary search for lists in erlang is wrong idea, because lists:nth/2 is not O(1) but O(N) operation. Try list_to_tuple/1 and than do it on tuple. It is much more worth work.
It can also be worth to try it on array module.
The function erlang:length/1 returns the length of a list.
You called length(1) and 1 isn't a list.
length([1]) would return 1
length([1,2,3,4[) would return 4
etc, etc...
It appears that combining the remarks from Ben Hughes solves the problem. Just for completeness I'm pasting the tests-passing implementation of my binary search below.
chop(_,[]) -> -1;
chop(N,L) ->
Array = array:from_list(L),
chop(N,Array, 0, array:size(Array)-1).
chop(N, L, K, K) ->
Element = array:get(K,L),
if
Element == N -> K;
true -> -1
end;
chop(_, _, K, M) when M < K -> -1;
chop(N, L, K, M) ->
MidIndex = K + ((M - K) div 2),
MidPoint = array:get(MidIndex,L),
case MidPoint of
N -> MidIndex;
_ when MidPoint < N -> chop(N,L,MidIndex+1,M);
_ -> chop(N,L,K,MidIndex-1)
end.