Cut from negative integer to last item in list in Hy - hy

If (list (range 10)) is [0 ... 9], and (cut (list (range 10)) -5 -1) is [5, 6, 7, 8], then how do I include the last item in the list as well, i.e. [5, 6, 7, 8, 9]? I've tried (cut (list (range 10)) -5 0) and (cut (list (range 10)) -5 1), but both give me empty lists.

You need to use None as the stop argument, as in (cut (list (range 10)) -5 None). The difference between (cut x -5) and (cut x -5 None) is the same as between x[slice(-5)] and x[slice(-5, None)] in Python, or equivalently x[:-5] and x[-5:].

Related

Ruby sorting even and odd numbers issue

I'm learning Ruby and just started with the sorting. Trying to sort the array like this: [1,3,5,2,4,6] and I'm don't really understand what is wrong with the code. Any help would be appreciated!
[1,2,3,4,5,6].sort do |x,y|
if x.odd? and y.odd?
0
elsif x.odd?
-1
else
1
end
if (x.odd? && y.odd?) or (x.even? && y.even?)
x <=> y
end
end
First off, let's fix your indentation (and convert to standard Ruby community coding style), so that we can better see what's going on:
[1, 2, 3, 4, 5, 6].sort do |x, y|
if x.odd? && y.odd?
0
elsif x.odd?
-1
else
1
end
if (x.odd? && y.odd?) || (x.even? && y.even?)
x <=> y
end
end
Now, the problem becomes obvious: your first conditional expression evaluates to 0, -1, or 1, but nothing is being done with this value. The value is not stored in a variable, not passed as an argument, not returned. It is simply ignored. The entire expression is a NO-OP.
Which means that the only thing that matters is this:
if (x.odd? && y.odd?) || (x.even? && y.even?)
x <=> y
end
This will return 0 for two elements that are equal, -1 or 1 for two elements that are unequal but both odd or both even, and nil (which to sort means "these two elements are un-comparable, they don't have a defined relative ordering") for elements where one element is odd and one is even. Since sort requires all elements to be comparable, it will then abort.
The easiest way to approach this problem would probably be to partition the array into odds and evens, sort them separately, and then concatenate them:
[1, 2, 3, 4, 5, 6].partition(&:odd?).map(&:sort).inject(:concat)
#=> [1, 3, 5, 2, 4, 6]
Or do it the other way round, just sort them all, and then partition (Thanks #Eric Duminil):
[1, 2, 3, 4, 5, 6].sort.partition(&:odd?).inject(:concat)
#=> [1, 3, 5, 2, 4, 6]
It's probably the first time I ever used a negative modulo :
i % -2 is -1 if i is odd
i % -2 is 0 if i is even
So sorting by i % -2 first and then by i should achieve the desired result.
If you want even numbers before odd numbers, you can sort by i % 2.
[3, 2, 1, 5, 6, 4].sort_by{ |i| [ i % -2, i] }
#=> [1, 3, 5, 2, 4, 6]
Thanks to #Stefan for his original idea!

How to group consecutive integers in a scala array?

Let’s say I have an array like the following:
1 2 3 4 5 6 7 8 9 1 2 3 4 5 1 2 3 4
I want many sub-arrays of contiguous numbers whose sum of every contiguous pair is less than 10
1 2 3 4 5, 6, 7, 8, 9, 1 2 3 4 5 1 2 3 4
How do I code it in scala in a functional idiomatic way?
// example no. 1
>Array(1, 2, 3, 4, 5, 6)...???
res0: List(Array(1, 2, 3, 4, 5), Array(6))
// example no. 2
>Array(3, 8, 1, 9, 1, 3)...???
res1: List(Array(3), Array(8, 1), Array(9), Array(1, 3))
Doing a foldRight makes it easier to use head and tail to build the resulting List.
val grouped = Array(3,8,1,9,1,3).foldRight(List.empty[Array[Int]]){case (n,acc) =>
if (acc.isEmpty) List(Array(n))
else if (acc.head.head + n < 10) n +: acc.head :: acc.tail
else Array(n) :: acc
} // List(Array(3), Array(8, 1), Array(9), Array(1, 3))
This should work (although it's a very inefficient way):
def group(threshold: Int)(seq: Seq[Int]): Seq[Seq[Int]] =
seq.reverse.tails.find(_.sum < threshold) match {
case None => Nil
case Some(Nil) => Nil
case Some(subSeq) =>
subSeq.reverse +: group(threshold)(seq.drop(subSeq.size))
}
group(10)(Array(3, 8, 1, 9, 1, 3))
List(Array(3), Array(8, 1), Array(9), Array(1, 3))

How do I count the number of elements in my array that are unique and are bigger than the element before them?

I'm using Ruby 2.4. I have an array of strings taht are all numbers. I want to count the number of elements in the array that are unique and that are also greater than the element before them (I consider the first array element already greater than its non-existent predecessor). So I tried
data_col = ["3", "6", "10"]
#=> ["3", "6", "10"]
data_col.map { |string| string.to_i.to_s == string ? string.to_i : -2 }.each_cons(2).select { |a, b| a > b && data_col.count(a) == 1 }.count
#=> 0
but the results is zero, despite the fact that all the elements in my array satisfy my criteria. How can I improve the way I count this?
require 'set'
def nbr_uniq_and_bigger(arr)
processed = Set.new
arr.each_cons(2).with_object(Set.new) do |(n,m),keepers|
if processed.add?(m)
keepers << m if m > n
else
keepers.delete(m)
end
end.size + (processed.include?(arr.first) ? 0 : 1)
end
nbr_uniq_and_bigger [1, 2, 6, 3, 2]
#=> 2
nbr_uniq_and_bigger [1, 2, 1, 2, 1, 2]
#=> 0
See Set.add?.
Note the line keepers.delete(m) could be written
keepers.delete(m) if keepers.key(m)
but attempting to delete an element not in the set does not harm.
There are a few things wrong here:
a > b seems like the opposite of what you want to test. That should probably be b > a.
If I followed properly, I think data_col.count(a) is always going to be zero, since a is an integer and data_col contains only strings. Also, I'm not sure you want to be looking for a... b is probably the right element to look for.
I'm not sure you're ever counting the first element here. (You said you consider the first element to be greater than its non-existent predecessor, but where in your code does that happen?)
Here's some code that works:
def foo(x)
([nil] + x).each_cons(2).select { |a, b| (a == nil or b > a) and x.count(b) == 1 }.count()
end
p foo([3, 6, 10]) # 3
p foo([3, 6, 10, 1, 6]) # 2
(If you have an array of strings, feel free to do .map { |s| s.to_i } first.)
One more solution:
def uniq_and_bigger(data)
counts = data.each_with_object(Hash.new(0)) { |e, h| h[e] += 1 } #precalculate
data.each_cons(2).with_object([]) do |(n,m), a|
a << m if m > n && counts[m] == 1
end.size + (counts[data[0]] == 1 ? 1 : 0)
end
uniq_and_bigger([3, 6, 10, 1, 6])
=> 2
uniq_and_bigger([1, 2, 1, 2, 1, 2])
=> 0
Yet another solution. It's O(n) and it returns the desired result for [3, 6, 10].
It uses slice_when :
def unique_and_increasing(array)
duplicates = array.group_by(&:itself).select{ |_, v| v.size > 1 }.keys
(array.slice_when{ |a, b| a < b }.map(&:first) - duplicates).size
end
p unique_and_increasing [3, 6, 10]
# 3
p unique_and_increasing [3, 6, 10, 1, 6]
# 2
p unique_and_increasing [1, 2, 1, 2, 1, 2]
# 0

Ruby 2.0.0 Array#bsearch behavior

I noticed that as of Ruby 2.0.0 the array class has a bsearch method that I was testing and I'm not getting the behavior I'd expect. Why does it return a value for 2 and 5 but nil for -1, 1, and 4?
arr_in = [-1, 1, 2, 4, 5]
arr_in.bsearch { |x| x == 3 } #=> nil
arr_in.bsearch { |x| x == -1 } #=> nil
arr_in.bsearch { |x| x == 1 } #=> nil
arr_in.bsearch { |x| x == 2 } #=> 2
arr_in.bsearch { |x| x == 4 } #=> nil
arr_in.bsearch { |x| x == 5 } #=> 5
arr_in = [-1, 1,2,4,5]
arr_in.bsearch{ |x| 2 - x }
#=> 2
arr_in.bsearch{ |x| -1 - x }
#=> -1
arr_in.bsearch{ |x| 3 - x }
#=> nil
Binary search uses block's result as a hint which part of array (left or right side) should be chosen for searching on next iteration. If block returns 0 it will stop searching. If it returns less then 0 it will go left otherwise it goes right :)
More information here
http://www.ruby-doc.org/core-2.1.1/Array.html#method-i-bsearch
UPD
Ok, let's take your example
arr_in = [-1, 1, 2, 4, 5]
arr_in.bsearch { |x| x == 3 }
First we will take middle element (2) and yield it to the block. 2 == 3 will return false, so we move to the right side of the array.
We take middle element of [4, 5] which is 5 and 5 == 3 is false
There is no any elements on the right, so we will return nil
arr_in = [-1, 1, 2, 4, 5]
arr_in.bsearch { |x| x == 2 }
First 2 == 2 is true. We go to the left.
Middle element of [-1, 1] is 1. 1 == 2 is false. We go to the right.
There is no any elements in [-1, 1] right to the 1, so we return last last element which returned true statement which is 2
PS: don't forget, that the array should be sorted ;)
I find it more intuitive to use the spaceship operator
array.bsearch {|x| 3 <=> x }
Just make sure to put the x to the right of the spaceship.
The reason why is that the thing being compared against during each iteration is the left-hand operand. So if you want to find a 3, you need to continually compare against a 3, in order to get the correct left, right, or equal result. If you put the variable on the left (as one might intuitively to do), you've reversed the comparison output, foiling the bsearch algorithm!
This also works for strings and any object that is comparable with <=>.

clojure for loop, store the values in a set or map

This one has been bothering me for a while now,
How should we store a value in a set or map in a for loop?
(let [s #{}]
(for [ i (range 10)
j (range 10) ]
(into s [i j])))
i know this will not work, but i want a functionality similar to this , where the set will finally contain [0 0] [0 1]...[0 9] [1 0]...[9 9]
Thanks
If I understand your question correctly you need to turn your expression inside-out:
(let [s #{}]
(into s (for [i (range 10)
j (range 10)]
[i j])))
The thing to realize here is that for returns a value (a lazy sequence) unlike for-loops in more imperative languages like Java and C.
Is this what you want?
(into #{} (for [i (range 10) j (range 10)]
[i j]))
;-> #{[2 1] [3 2] [4 3] [5 4] [6 5] [7 6] [8 7] [9 8] [1 0]
; [2 2] [3 3] [4 4] [5 5] [6 6]...
And if you just want the list as a set:
(set (for [i (range 10) j (range 10)]
[i j]))
You will end up with a set of pairs.
Generally when you want to return a set or a map or other 'single value' that isn't a seq from a 'repeated' generalized operation on a seq, using reduce is more idiomatic/straightforward than loop/recur, and for always returns a seq (not a set or map).
(reduce conj #{} (for [i (range 10) j (range 10)] [i j]))
note that (for ..) here is only used to produce a seq containing all the values to compile into the single result set. Or, for example:
(reduce + 0 (range 100))
=> 4950
clojure has a several great systems for managing mutable state. in this case you may want an atom containing a set
your other options are:
a ref if more than one change needs to made (coordinated many threads)
a var if this will be single threaded (a var may work just as well here as an atom)
an agent if you wanted to set the value of s asynchronously
of course for returns a sequence already so you may just want
(into #{} (for [ i (range 10)
j (range 10) ]
[i j]))
I think you can also use some transient data structure in this scenario.
(let [s (transient #{})]
(for [ i (range 10)
j (range 10) ]
(assoc! s i j)))
(persistent! s)
Just a code sample, not tested.

Resources