If I have a sorted array of numerical values such as Double, Integer, and Time, what is the general logic to finding a complement?
Over my CS career in college, I've gotten better of understanding complements and edge cases for ranges. As I help students whose skill levels and understanding match mine when I wrote this, I need help finding a generalized way to convey this concept to them for singular elements and ranges.
Try something like this:
def complement(l, universe=None):
"""
Return the complement of a list of integers, as compared to
a given "universe" set. If no universe is specified,
consider the universe to be all integers between
the minimum and maximum values of the given list.
"""
if universe is not None:
universe = set(universe)
else:
universe = set(range(min(l), max(l)+1))
return sorted(universe - set(l))
then
l = [1,3,5,7,10]
complement(l)
yields:
[2, 4, 6, 8, 9]
Or you can specify your own universe:
complement(l, range(12))
yields:
[0, 2, 4, 6, 8, 9, 11]
To add another option - using a data type that is always useful to learn about, for these types of operations.
a = set([1, 3, 5, 7, 10])
b = set(range(1, 11))
c = sorted(list(b.symmetric_difference(a)))
print(c)
[2, 4, 6, 8, 9]
>>> nums = [1, 3, 5, 7, 10]
>>> [n + ((n&1)*2-1) for n in nums]
[2, 4, 6, 8, 9]
The easiest way is to iterate from the beginning of your list to the second to last element. Set j equal to the index + 1. While j is less than the next number in your list, append it to your list of complements and increment it.
# find the skipped numbers in a list sorted in ascending order
def getSkippedNumbers (arr):
complement = []
for i in xrange(0, len(arr) - 1):
j = arr[i] + 1
while j < arr[i + 1]:
complement.append(j)
j += 1
return complement
test = [1, 3, 5, 7, 10]
print getSkippedNumbers(test) # returns [2, 4, 6, 8, 9]
You can find the compliment of two lists using list comprehension. Here we are taking the complement of a set x with respect to a set y:
>>> x = [1, 3, 5, 7, 10]
>>> y = [1, 2, 3, 4, 8, 9, 20]
>>> z = [n for n in x if not n in y]
>>> z
[5, 7, 10]
>>>
Related
For an numpy 1d array such as:
In [1]: A = np.array([2,5,1,3,9,0,7,4,1,2,0,11])
In [2]: A
Out[2]: array([2,5,1,3,9,0,7,4,1,2,0,11])
I need to split the array by using the values as a sub-array length.
For the example array:
The first index has a value of 2, so I need the first split to occur at index 0 + 2, so it would result in ([2,5,1]).
Skip to index 3 (since indices 0-2 were gobbled up in step 1).
The value at index 3 = 3, so the second split would occur at index 3 + 3, and result in ([3,9,0,7]).
Skip to index 7
The value at index 7 = 4, so the third and final split would occur at index 7 + 4, and result in ([4,1,2,0,11])
I'm using this simple array as an example, because I think it will help in my actual use case, which is reading data from binary files (either as bytes or unsigned shorts). I'm guessing that numpy will be the fastest way to do it, but I could also use struct/bytearray/lists or whatever would be best.
I hope this makes sense. I had a hard time trying to figure out how best to word the question.
Here is an approach using standard python lists and a while loop:
def custom_partition(arr):
partitions = []
i = 0
while i < len(arr):
pariton_size = arr[i]
next_i = i + pariton_size + 1
partitions.append(arr[i:next_i])
i = next_i
return partitions
a = [2, 5, 1, 3, 9, 0, 7, 4, 1, 2, 0, 11]
b = custom_partition(a)
print(b)
Output:
[[2, 5, 1], [3, 9, 0, 7], [4, 1, 2, 0, 11]]
For example, we have such array arr = [1, 1, 3, 4, 5, 7] and we have given number 8, we need to find any n number of elements in this array that will be the sum of the given number. In this case, it should be [1, 3, 4] or [1, 7] or [3, 5]. What is the easiest way to do it in Ruby?
Like #Stefan and #Jorg said in comments there is no easy way to do it. If this was a question to myself, I would probably write down something like this.
arr = [1, 1, 3, 4, 5, 7]
number = 8
result = []
for i in 0..(arr.length) do
arr.combination(i).each do |combination|
result.push(combination) if combination.sum == number
end
end
print result.uniq
Depending on the magnitude of the given number, it may be faster to use dynamic programming. If tot is the given number and arr is the array of possible summands, the method given below has a computational complexity of O(tot*arr.size).
Code
def find_summands(arr, tot)
return [] if tot.zero?
arr.each_with_object([{tot=>nil}]) do |n,a|
h = a.last.each_key.with_object({}) do |t,h|
return soln(arr,a.drop(1),n) if t==n
h[t] = 0
h[t-n] = n
end
a << h
end
nil
end
def soln(arr,a,n)
t = n
a.reverse.each_with_object([n]) do |h,b|
m = h[t]
b << m
t += m
end.reverse.tap { |a| (arr.size-a.size).times { a << 0 } }
end
Examples
arr = [1, 1, 3, 4, 5, 7]
find_summands(arr, 8)
#=> [1, 0, 3, 4, 0, 0]
find_summands(arr, 11)
#=> [1, 1, 0, 4, 5, 0]
find_summands(arr, 21)
#=> [1, 1, 3, 4, 5, 7]
find_summands(arr, 22)
#=> nil
find_summands([1, -2, 3, 4, 5, 7], 6)
#=> [1, -2, 3, 4, 0, 0]
Each zero in the array returned indicates that the corresponding element in arr is not used in the summation.
Explanation
Suppose:
arr = [4, 2, 6, 3, 5, 1]
tot = 13
then
find_summands(arr, tot)
#=> [4, 0, 6, 3, 0, 0]
When a solution is obtained soln is called to put it into a more useful form:
soln(arr, a.drop(1), n)
Here, arr is as above and
n #=> 3
a #=> [
{13=>nil}, # for tot
{13=>0, 9=>4}, # for arr[0] => 4
{13=>0, 11=>2, 9=>0, 7=>2}, # for arr[1] => 2
{13=>0, 7=>0, 11=>0, 5=>6, 9=>0, 3=>6, 1=>6} # for arr[2] => 6
]
n equals the value of the last summand used from arr, left to right.
When considering arr[0] #=> 4 the remaining amount to be summed is 13, the key of a[0] #=> {13=>nil}. There are two possibilities, 4 is a summand or it is not. This gives rise to the hash
a[1]
#=> {13-0=>0, 13-4=>4}
# { 13=>0, 9=>4}
where the keys are the remaining amount to be summed and the value is 4 if 4 is a summand and is zero if it is not.
Now consider arr[1] #=> 2. We look to the keys of a[1] to see what the possible remaining amounts might be after 4 is used or not. (13 and 9). For each of these we consider using or not using 2. That gives rise to the hash
a[2]
#=> {13-0=>0, 13-2=>2, 9-0=>0, 9-2=>2}
# { 13=>0, 11=>2, 9=>0, 7=>2}
7=>2 can be read, if 2 (the value) is a summand, there is a choice of using arr[0] or not that results in the remaining amount to be summed after 2 is included being 7.
Next consider arr[2] #=> 6. We look to the keys of a[2] to see what the possible remaining amounts might be after 4 and 6 are used or not. (13, 11, 9 and 7). For each of these we consider using or not using 6. We therefore now create the hash
a[3]
#=> {13-0=>0, 13-6=>6, 11-0=>0, 11-6=>6, 9-0=>0, 9-6=>6, 7-0=>0, 7-6=>6}
# { 13=>0, 7=>6, 11=>0, 5=>6, 9=>0, 3=>6, 7=>0, 1=>6}
# { 13=>0, 11=>0, 5=>6, 9=>0, 3=>6, 7=>0, 1=>6}
The pair 11=>0 can be read, "if 6 is not a summand, there is a choice of using or not using arr[0] #=> 4 and arr[2] #=> 2 that results in the remaining amount to be summed after 6 is excluded being 11".
Note that the key-value pair 7=>6 was overwritten with 7=>0 when not using 6 was considered with a remaining amount of 7. We are only looking for one solution, so it doesn't matter how we get to a remaining amount of 7 after the first three elements of arr are considered. These collisions tend to increase as we move left-to-right in arr, so the number of states we need to keep track of is greatly reduced because we are able to "throw away" so many of them.
Lastly (as it turns out), we consider arr[3] #=> 3. We look to the keys of a[3] to see what the possible remaining amounts might be after 4, 2 and 6 have been used or not (13, 11, 5, 9, 3, 7 and 1). For each of these we consider using or not using 3. We get this far in creating the hash a[4]:
{13=>0, 10=>3, 11=>0, 8=>3, 5=>0, 2=>3, 9=>0, 6=>3, 3=>0, 0=>3}
As the last key-value pair has a key of zero we know we have found a solution.
Let's construct the solution. Because the value of 0 is 3, 3 is a summand. (We would have found the solution earlier if the value were zero.) We now work backwards. As 3 is used, the remaining amount before 3 is used is 0+3 #=> 3. We find that a[3][3] #=> 6, meaning 6 is also a summand. The remaining balance before using the 6 was 3+6 #=> 9, so we compute a[2][9] #=> 0, which tells us that the 2 is not a summand. Lastly, a[1][9-0] #=> 4 shows that 4 is also a summand. Hence the solution
[4, 0, 6, 3, 0, 0]
I had two list:
a=[0,0,0,1,1,1,1,2,2]
b=[2,5,12,2,3,8,9,4,6]
And I wanted to get:
c=[[0,2,5,12],[1,2,3,8,9],[2,4,6]]
A and b correlated to each other, a[i] related to b[i], when the value in a change like 0 to 1, 12 end in the first inner-list of c.
I tried it with if else statement but it failed
How to get c in python?
This code produces c in a good enough way (provided a and b are always adjusted in the same way as in the example):
a=[0,0,0,1,1,1,1,2,2]
b=[2,5,12,2,3,8,9,4,6]
c = []
i = 0
while i < len(a):
d = a.count(a[i])
c.append([a[i]] + b[i:i + d])
i += d
print(c) # ==> [[0, 2, 5, 12], [1, 2, 3, 8, 9], [2, 4, 6]]
We can zip the lists, group by first value from a, and make lists with the second:
from itertools import groupby
from operator import itemgetter
a=[0,0,0,1,1,1,1,2,2]
b=[2,5,12,2,3,8,9,4,6]
[list(map(itemgetter(1), group)) for _, group in groupby(zip(a, b), key=itemgetter(0))]
#[[2, 5, 12], [2, 3, 8, 9], [4, 6]]
Similar to #Thierry Lathuille's answer, but does actually prepend the keys to the sub lists as requested by OP:
import itertools as it
ib = iter(b)
[[k, *(next(ib) for _ in gr)] for k, gr in it.groupby(a)]
# [[0, 2, 5, 12], [1, 2, 3, 8, 9], [2, 4, 6]]
Here's my simple solution. Notice that you are splitting the list by by the counts of elemets in the list a. deque is used for popping elements in O(1) time from the left.
import itertools
from collections import Counter, deque
a = [0,0,0,1,1,1,1,2,2]
b = deque([2,5,12,2,3,8,9,4,6])
c = Counter(a)
new_list=[]
for x in c:
new_list.append([x]+[b.popleft() for i in range(a[x])])
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I'm trying to sum the value of two array elements from two separate arrays from end to beginning, to see if that sum is greater than 9.
I have tested my code and the part which doesn't work is.
if halfa[i] + halfb[i] > 9
Does anyone know where i'm going wrong? Any help would be much appreciated.
text = gets.chomp
half1 = text.slice(0,10)
half2 = text.slice(text.length - 10,text.length)
puts half1
puts half2
halfa = half1.split("")
halfb = half2.split("")
halfa.map! { |i| i.to_i }
halfb.map! { |i| i.to_i }
count = 0
for i in halfa.length.downto(0)
if halfa[i] + halfb[i] > 9
count += 1
end
end
print count
You've got an off-by-one error here, one of the classic programming mistakes, you start iterating at i being the length of the array, yet halfa[5] is nil, the array goes from 0 to 4.
The problem here is you're using the clunky for loop method for iterating. Ruby, unlike nearly every other language, shuns that in favour of using iterator methods:
halfa.each_index do |i|
if halfa[i] + halfb[i] > 9
count += 1
end
end
That's the most literal translation of what you have. Note you can clean up your code considerably if it's expressed in a more Ruby-like notation:
text = "4443466664"
# Define a variable here that represents the slice size to use
slice_size = 5
# Cut this into groups of 5 characters, convert each chunk by remapping
# the values to integers, then save it all into one variable.
halves = text.chars.each_slice(slice_size).map { |a| a.map(&:to_i) }
# The result looks like this:
# => [[4, 4, 4, 3, 4], [6, 6, 6, 6, 4]]
# Count all pairs that add up to more than 9 using count with a block
# that defines when to count them. Note the use of ... which goes up to
# but does not include the upper bound.
count = (0...slice_size).count do |i|
halves[0][i] + halves[1][i] > 9
end
# => 3
One way to refactor your code would be with Array#zip and Enumerable#count:
text = "123456789098765"
n = 10
digits = text.chars.map(&:to_i)
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 9, 8, 7, 6, 5]
first = digits.first(n)
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
last = digits.last(n)
# [6, 7, 8, 9, 0, 9, 8, 7, 6, 5]
pairs = first.zip(last)
# [[1, 6], [2, 7], [3, 8], [4, 9], [5, 0], [6, 9], [7, 8], [8, 7], [9, 6], [0, 5]]
count = pairs.count{ |a, b| a + b > 9 }
# 6
for i in halfa.length.downto(0) : halfa.length is 10, but arrays have zero-based indices: start counting with 0. halfa[10] does not exist.
for i in (halfa.length-1).downto(0) will result in - well, at least something.
Your for loop is going to start at halfa.length, which is 10. The highest index in in halfa is 9, so halfa[10] returns nil.
You could fix it by changing halfa.length to (halfa.length - 1), but you would still have some very unidiomatic code. In Ruby it's rare to see for, because there is pretty much always a better alternative. For example:
text = "31415926535897932384"
half_size = text.size / 2
count = half_size.times.count do |i|
text[i].to_i + text[i+half_size].to_i > 9
end
puts count
# => 4
The above code assumes that the text will have an even number of characters. You could also hard-code half_size to 10 if you wanted.
The Integer#times method will enumerate the numbers 0 through its receiver, so e.g. 5.times.to_a returns [0, 1, 2, 3, 4]. The Array#count method returns the number of times the block yielded a truthy value.
See it on repl.it: https://repl.it/FXpa
I've got this question from an Interview in Microsoft: Given an unsorted array, Find the maximum subtraction between two elements in the array is a way that:
(Index1, Index2) = arr[Index2] - arr[Index1]. Index1<Index2.
Example:
given the array: [1, 5, 3, 2, 7, 9, 4, 3] -> Output: (1,9)=8.
given the array: [4, 9, 2, 3, 6, 3, 8, 1] -> Output: (2,8)=6.
The naive solution works in O(n^2) times: Scan the first index for subtraction with all other indexes and save the max value, Continue to the next index and so on.
Is there any way to optimize this?
Fairly simple when you write it down. Rephrasing the problem, you want to find the largest element to the right of each element. Now given the first example, this is:
[1, 5, 3, 2, 7, 9, 4, 3]
=>
[9, 9, 9, 9, 9, 4, 3]
Now, notice the maximums array is just the cumulative maximums from the right. Given this property it is easy to construct an O(n) time algorithm.
Implementation in python:
def find_max(xs):
ys = []
cur_max = float('-inf')
for x in reversed(xs):
cur_max = max(x, cur_max)
ys.append(cur_max)
ys = ys[::-1][1:]
return max(y - x for x, y in zip(xs, ys))
We can also construct the maximums array lazily, doing so gives us O(1) memory, which is the best possible:
def find_max(xs):
cur_max = float('-inf')
cum_max = xs[-1]
for i in range(len(xs) - 2, -1, -1):
cur_max = max(cur_max, cum_max - xs[i])
cum_max = max(cum_max, xs[i])
return cur_max
I think this is correct and O(nlogn): Split in the middle and select from right the max, from left the min value. Also split the the other 2 quarters, if one of them gives bigger result continue on that branch recursively.
Second example:
4, 9, 2, 3| 6, 3, 8, 1 -> 2 and 8
4, 9| 2, 3, 6, 3, 8, 1 -> 4 and 8
4, 9, 2, 3, 6, 3| 8, 1 -> 2 and 8
So working on the right split:
4, 9, 2, 3, 6, 3, 8| 1 -> 2 and 1
Selecting the 2 and 8 option. It also works for the first example.