I have an array like:
A = [1,3,8,9,3,7,2,1,3,9,6,8,3,8,8,1,2]
And I want to count the number of "entry clusters" that are >5. In this case the result should be 4, because:
[1, 3, (8,9), 3, (7), 2, 1, 3, (9,6,8), 3, (8,8), 1, 2]
Given L length of the array, I can do:
A = [1,3,8,9,3,7,2,1,3,9,6,8,3,8,8,1,2]
A = np.array(A)
for k in range(0,L):
if A[k]>5:
print k, A[k]
and this gives me all entries greater than 5. But how could I group every cluster of numbers?
You could use the groupby function from itertools.
from itertools import groupby
A = [1,3,8,9,3,7,2,1,3,9,6,8,3,8,8,1,2]
result = [tuple(g) for k, g in groupby(A, lambda x: x > 5) if k]
print(result)
# [(8, 9), (7,), (9, 6, 8), (8, 8)]
print(len(result))
# 4
Related
Given an array arr and a partition value k, I need to divide it into k parts such that the difference between the product of maximum value of each part times number of values in each part is minimized.
For example:
arr = [5,6,7,8,9,1,2,3,4]
k = 3
Dividing the above array into 3 parts producing the desired result is:
[[1,2,3,4],[5,6,7],[8,9]]
[1,2,3,4] = max([[1,2,3,4]) * 4 = 16
[5,6,7] = max([5,6,7]) * 3 = 21
[8,9] = max([8,9]) * 2 = 18
The max difference in this partition is 21-16 = 5.
This is the "least" difference I can get partitioning them.
First thing we need to do is figure out how to split the list into partitions.
To get all of the ways we can split the list into k sections, we can start by determine all of the ways k numbers can add up to len(arr), where each number is greater than 1.
To do so we can take advantage of itertools.
def partition_index(a, k):
for indices in product(range(1, len(a)), repeat=k):
if sum(indices) == len(a):
yield indices
for s in partition_index([9, 1, 2, 3, 4], 3):
print(s)
(1, 1, 3)
(1, 2, 2)
(1, 3, 1)
(2, 1, 2)
(2, 2, 1)
(3, 1, 1)
Perfect! Now if we want to split our array based on these values, it'll be easier if we turn them into tuples for the start and end of where to split. For this we can use itertools again!
def partition_index(a, k):
for indices in product(range(1, len(a)), repeat=k):
if sum(indices) == len(a):
yield list(pairwise([0, *accumulate(indices)]))
[(0, 1), (1, 2), (2, 5)]
[(0, 1), (1, 3), (3, 5)]
[(0, 1), (1, 4), (4, 5)]
[(0, 2), (2, 3), (3, 5)]
[(0, 2), (2, 4), (4, 5)]
[(0, 3), (3, 4), (4, 5)]
Now that we have this grouping, creating a method to do the partition is pretty straight forward:
def partition(a, k):
for indices in partition_index(a, k):
yield [a[i:j] for i, j in indices]
[[9], [1], [2, 3, 4]]
[[9], [1, 2], [3, 4]]
[[9], [1, 2, 3], [4]]
[[9, 1], [2], [3, 4]]
[[9, 1], [2, 3], [4]]
[[9, 1, 2], [3], [4]]
And finally we can use this output to get your desired results.
def minimized_difference(a, k):
final_diff, final_result = None, None
for result in partition(a, k):
result_max = [max(r) * len(r) for r in result]
diff = max(result_max) - min(result_max)
if final_diff is None or diff < final_diff:
final_diff, final_result = diff, result
return final_result
print(minimized_difference([5, 6, 7, 8, 9, 1, 2, 3, 4], 3))
[[5, 6, 7], [8, 9], [1, 2, 3, 4]]
Final code with some refactoring and covering corner cases:
from itertools import pairwise, product, accumulate
from typing import TypeVar, Iterable, Optional
T = TypeVar('T')
def partition_index(size: int, k: int) -> Iterable[list[tuple[int, int]]]:
for indices in product(range(1, size - k + 2), repeat=k):
if sum(indices) == size:
yield list(pairwise([0, *accumulate(indices)]))
def partition(data: list[T], k: int) -> Iterable[list[list[T]]]:
if len(data) < k or k <= 0:
return
for indices in partition_index(len(data), k):
yield [data[i:j] for i, j in indices]
def evaluate_result(result: list[list[T]]) -> int:
result_max = [max(r) * len(r) for r in result]
return max(result_max) - min(result_max)
def minimized_difference(data: list[int], k: int) -> Optional[list[list[int]]]:
return min(partition(data, k), default=None, key=evaluate_result)
print(minimized_difference([5, 6, 7, 8, 9, 1, 2, 3, 4], 3))
I'm trying to solve this exercise in my coursework:
Create a function named detect_ranges that gets a list of integers as a parameter.
The function should then sort this list, and transform the list into another list where pairs are used for all the detected intervals.
So 3,4,5,6 is replaced by the pair (3,7).
Numbers that are not part of any interval result just single numbers.
The resulting list consists of these numbers and pairs, separated by commas. An example of how this function works:
print(detect_ranges([2,5,4,8,12,6,7,10,13]))
[2,(4,9),10,(12,14)]
I couldn't comprehend the exercise topic and can't think of how I can detect range. Do you guys have any hints or tips?
Another way of doing this. Although this method will not be as efficient as the other one, but since its an exercise, it will be easier to follow.
I have used zip function in python to do some stuff I explained below, you can check it here to know more about it.
1. First sort the list data, so you get: [2, 4, 5, 6, 7, 8, 10, 12, 13]
2. Then find the differences of increasing values in list. Like (4-2),(5-4), .. If the difference is <=1, then it will be part of a range:
(Also, insert a 0 in the front, just to account for the 1st element and make the obtained list's length equal to original list)
>>> diff = [j-i for i, j in zip(lst[:-1], lst[1:])]
>>> diff.insert(0, 0)
>>> diff
[0, 2, 1, 1, 1, 1, 2, 2, 1]
3. Now get positions in above list where difference is >= 2. This is to detect the ranges:
(Again, insert a 0 in the front, just to account for the 1st element, and make sure it gets picked in range detection)
>>> ind = [i for i,v in enumerate(diff) if v >= 2]
>>> ind.insert(0, 0)
>>> ind
[0, 1, 6, 7]
So the ranges are 0 to 1, 1 to 6, and 6 to 7 in your original list.
4. Group the elements together that will form ranges, using the ind list obtained:
>>> groups = [lst[i:j] for i,j in zip(ind, ind[1:]+[None])]
>>> groups
[[2], [4, 5, 6, 7, 8], [10], [12, 13]]
5. Finally obtain your desired ranges:
>>> ranges = [(i[0],i[-1]+1) if len(i)>1 else i[0] for i in groups]
>>> ranges
[2, (4, 9), 10, (12, 14)]
Putting it all in a function detect_ranges:
def detect_ranges(lst):
lst = sorted(lst)
diff = [j-i for i, j in zip(lst[:-1], lst[1:])]
diff.insert(0, 0)
ind = [i for i,v in enumerate(diff) if v >= 2]
ind.insert(0, 0)
groups = [lst[i:j] for i,j in zip(ind, ind[1:]+[None])]
ranges = [(i[0],i[-1]+1) if len(i)>1 else i[0] for i in groups]
return ranges
Examples:
>>> lst = [2,6,1,9,3,7,12,45,46,13,90,14,92]
>>> detect_ranges(lst)
[(1, 4), (6, 8), 9, (12, 15), (45, 47), 90, 92]
>>> lst = [12,43,43,11,4,3,6,6,9,9,10,78,32,23,22,98]
>>> detect_ranges(lst)
[(3, 5), (6, 7), (9, 13), (22, 24), 32, (43, 44), 78, 98]
Iterate through the elements and save the start of each interval.
def detect_ranges(xs):
it = iter(xs)
try:
start = next(it)
except StopIteration:
return
prev = start
for x in it:
if prev + 1 != x:
yield start, prev + 1
start = x
prev = x
yield start, prev + 1
Usage:
>>> xs = [2, 4, 5, 6, 7, 8, 10, 12, 13]
>>> ranges = list(detect_ranges(xs))
>>> ranges
[(2, 3), (4, 9), (10, 11), (12, 14)]
If you want to reduce single item intervals like (2, 3) to 2, you can do:
>>> ranges = [a if a + 1 == b else (a, b) for a, b in ranges]
>>> ranges
[2, (4, 9), 10, (12, 14)]
I am making combination of six number is seems easy but i need output of specific combination
i think i need to use count function and loop?????
from itertools import combinations
comb = combinations([1, 2, 3, 4, 5, 6], 3)
for n in list(comb):
print (n)
Actual result give me 20 combination, but i need solution of code gives me only combination n where n(n1,n2,n3) n1+n2=n3,
so in my case it will be
(1,2,3) (1,3,4) (1,4,5) (1,5,6) (2,3,5) (2,4,6)
i need solution of code gives me only combination n where n(n1,n2,n3) n1+n2=n3
Add that as an if statement inside the for loop:
for n in comb:
if n[0] + n[1] == n[2]:
print (n)
Try this oneliner:
from itertools import combinations as combs
print(list(filter(lambda c: c[0]+c[1]==c[2], combs(range(1,7), 3))))
Or if your want to print one combination at a time you can do:
from itertools import combinations as combs
for comb in filter(lambda c: c[0]+c[1]==c[2], combs(range(1,7), 3)):
print(comb)
Another solution:
result = [(x,y,z) for (x,y,z) in combinations([1, 2, 3, 4, 5, 6], 3) if x+y==z]
print(result)
[(1, 2, 3), (1, 3, 4), (1, 4, 5), (1, 5, 6), (2, 3, 5), (2, 4, 6)]
Given two lists of equal length:
_list = [1, 4, 8, 7, 3, 15, 5, 0, 6]
_list2 = [7, 4, 0, 1, 5, 5, 7, 2, 2]
How do I try getting an output like this:
output = [(0,3), (1,1), (3,0), (6,4), (6,5), (7,2)]
Here the intersection of two lists are obtained and the common elements' indices are arranged in the list:
output = list of (index of an element in _list, where it appears in _list2)
Trying intersection with sets is not an option since the set removes the repeating elements.
Basic-Intermediate: As a generator:
def find_matching_indices(a, b):
for i, x in enumerate(a):
for j, y in enumerate(b):
if x == y:
yield i, j
list(find_matching_indices(list1_, list2_))
# [(0, 3), (1, 1), (3, 0), (3, 6), (6, 4), (6, 5), (7, 2)]
Basic-Intermediate: As a list comprehension:
[(i, j) for i, x in enumerate(list1_) for j, y in enumerate(list2_) if x == y]
# [(0, 3), (1, 1), (3, 0), (3, 6), (6, 4), (6, 5), (7, 2)]
These solutions involve two loops.
Intermediate-Advanced: For fun, a dictionary is another data structure you might consider:
import collections as ct
import more_itertools as mit
def locate_indices(a, b):
"""Return a dictionary of `a` index keys found at `b` indices."""
dd = ct.defaultdict(list)
for i, y in enumerate(a):
idxs = list(mit.locate(b, lambda z: z == y))
if idxs: dd[i].extend(idxs)
return dd
locate_indices(list1_, list2_)
# defaultdict(list, {0: [3], 1: [1], 3: [0, 6], 6: [4, 5], 7: [2]})
Note the index of list a is the key in the dictionary. All indices in list b that share the same value are appended.
A defaultdict was used since it is helpful in building dictionaries with list values. See more on the third-party tool more_itertools.locate(), which simply yields all indices that satisfy the lambda condition - an item in list a is also found in b.
from itertools import product
from collections import defaultdict
def mathcing_indices(*lists):
d = defaultdict(lambda: tuple([] for _ in range(len(lists))))
for l_idx, l in enumerate(lists):
for i, elem in enumerate(l):
d[elem][l_idx].append(i)
return sorted([tup for _, v in d.items() for tup in product(*v)])
This solution builds a dictionary that tracks the indices that values appear at in the input lists. So if the value 5 appears at indices 0 and 2 of the first list and index 3 of the second, the value for 5 in the dictionary would be ([0, 2], [3])
It then uses itertools.product to build all the combinations of those indices.
This looks more complicated than the other answers here, but because it is O(nlogn) and not O(n**2) it is significantly faster, especially for large inputs. Two length 1000 lists of random numbers 0-1000 complete 100 tests in ~.4 seconds using the above algorithm and 6-13 seconds using some of the others here
Here is a solution that runs in O(n log n):
ind1 = numpy.argsort(_list)
ind2 = numpy.argsort(_list2)
pairs = []
i = 0
j = 0
while i<ind1.size and j<ind2.size:
e1 = _list[ind1[i]]
e2 = _list2[ind2[j]]
if e1==e2:
pairs.append((ind1[i],ind2[j]))
i = i + 1
j = j + 1
elif e1<e2:
i = i +1
elif e2<e1:
j = j + 1
print(pairs)
How can I print the most common element of a list without importing a library?
l=[1,2,3,4,4,4]
So I want the output to be 4.
You can get the unique values first:
l = [1, 2, 3, 4, 4, 4]
s = set(l)
then you can create list of (occurrences, value) tuples
freq = [(l.count(i), i) for i in s] # [(1, 1), (1, 2), (1, 3), (3, 4)]
get the "biggest" element (biggest number of occurrences, the biggest value if there are more than one with the same number of occurrences):
result = max(freq) # (3, 4)
and print the value:
print(result[1]) # 4
or as a "one-liner" way:
l = [1, 2, 3, 4, 4, 4]
print(max((l.count(i), i) for i in set(l))[1]) # 4
lst=[1,2,2,2,3,3,4,4,5,6]
from collections import Counter
Counter(lst).most_common(1)[0]
Counter(lst) returns a dict of element-occurence pairs. most_common(n) returns the n most common elements from the dict, along with the number of occurences.