Let's say I've got a list of lists (or more conceptually accurate a 2D array):
list = [[1,1,0,0,0],
[1,1,2,0,0],
[0,2,2,2,0],
[0,0,0,2,0],
[0,0,0,1,0]]
I'd like to identify the different regions of identical values and rewrite the list so that each region has a unique value, like so:
list = [[1,1,2,2,2],
[1,1,3,2,2],
[0,3,3,3,2],
[0,0,0,3,2],
[0,0,0,4,2]]
I've mostly tried writing variations of a loop parsing the array per value and setting adjacent values equal to each other (which yea, is redundant I guess), BUT ensuring that island of 1s in the top left is distinct from the 1 in the bottom right was just not working. My attempts were spotty at best and non-functional at worst. Examples:
for x in list_length:
for y in sublist_length:
try:
if list[x][y] == list[x+1][y]:
list[x+1][y] = list[x][y]
except:
pass
or
predetermined_unique_value = 0
for x in list_length:
for y in sublist_length:
try:
if list[x][y] == list[x+1][y]:
list[x+1][y] = predetermined_unique_value
predetermined_unique_value += 1
except:
pass
and many slight variations on which directions (up, down, left, right from current spot/point) to check, brute forcing the loop by running it until all spots had been assigned a new value, etc.
Clearly I am missing something here. I suspect the answer is actually super simple, but I can't seem to find anything on google or reddit, or other answers here (I'm probably just conceptualizing it weirdly so searching for the wrong thing).
Just to reiterate, how could you parse that list of lists to organize values into adjacent regions based on identical data and rewrite it to ensure that those regions all have unique values? (I.E. so that there is only one region of the 0 value, one region of the 1 value, etc. etc.)
I hope this is enough information to help you help me, but in truth I just as much am not sure how to do this as I am doing it wrong. Please don't hesitate to ask for more.
Based on this answer you can do it with ndimage from the scipy library.
I applied your data to his answer and that's what I got as result:
from scipy import ndimage
import numpy as np
data_tup = ((1,1,0,0,0),
(1,1,2,0,0),
(0,2,2,2,0),
(0,0,0,2,0),
(0,0,0,1,0))
data_list = [[1,1,0,0,0],
[1,1,2,0,0],
[0,2,2,2,0],
[0,0,0,2,0],
[0,0,0,1,0]]
def find_clusters(array):
clustered = np.empty_like(array)
unique_vals = np.unique(array)
cluster_count = 0
for val in unique_vals:
labelling, label_count = ndimage.label(array == val)
for k in range(1, label_count + 1):
clustered[labelling == k] = cluster_count
cluster_count += 1
return clustered, cluster_count
clusters, cluster_count = find_clusters(data_list)
clusters_tup, cluster_count_tup = find_clusters(data_tup)
print(" With list of lists, Found {} clusters:".format(cluster_count))
print(clusters, '\n')
print(" With tuples of tuple, Found {} clusters:".format(cluster_count_tup))
print(clusters_tup)
Output:
With list of lists, Found 5 clusters:
[[2 2 0 0 0]
[2 2 4 0 0]
[1 4 4 4 0]
[1 1 1 4 0]
[1 1 1 3 0]]
With tuples of tuple, Found 5 clusters:
[[2 2 0 0 0]
[2 2 4 0 0]
[1 4 4 4 0]
[1 1 1 4 0]
[1 1 1 3 0]]
Both times the Output is a list of list. If you wish to have it different, the function needs to be changed inside.
You can use skimage.measure.label:
>>> import numpy as np
>>> from skimage import measure
>>>
>>> a = np.array([[1,1,0,0,0],
[1,1,2,0,0],
[0,2,2,2,0],
[0,0,0,2,0],
[0,0,0,1,0]])
>>> measure.label(a, background=a.max()+1)
array([[1, 1, 2, 2, 2],
[1, 1, 3, 2, 2],
[4, 3, 3, 3, 2],
[4, 4, 4, 3, 2],
[4, 4, 4, 5, 2]])
Note that the label function has an argument connectivity which determines how blobs/clusters are identified. The default for a 2D array is to consider diagonal neighbors. If that is undesired, connectivity=1 will consider only horizontal/vertical neighbors.
I'm not sure how good the performance of this solution is but here's a recursive approach to identify a connected segment. It will take a coordinate and return the same list of islands with every coordinate that was part of the same island as the given coordinate with True.
islands = [[1,1,0,0,0],
[1,1,2,0,0],
[0,2,2,2,0],
[0,0,0,2,0],
[0,0,0,0,0]]
def print_islands():
for row in islands:
print(row)
def get_bool_map(i, j):
checked_indexes = [[False] * len(islands[0]) ] * len(islands)
checked_cords = []
def check_island_indexes(island_value, m, i, j):
if i < 0 or j < 0:
return
try:
if m[i][j] != island_value:
return
else:
if [i, j] in checked_cords:
return
else:
checked_cords.append([i, j])
m[i][j] = True
except IndexError:
return
check_island_indexes(island_value, m, i - 1, j)
check_island_indexes(island_value, m, i + 1, j)
check_island_indexes(island_value, m, i, j - 1)
check_island_indexes(island_value, m, i, j + 1)
check_island_indexes(islands[i][j], islands, i, j)
get_bool_map(0, 4)
print_islands()
[1, 1, True, True, True]
[1, 1, 2, True, True]
[0, 2, 2, 2, True]
[0, 0, 0, 2, True]
[0, 0, 0, 1, True]
Given an array of scores sorted in increasing order, return true if the array contains 3 adjacent scores that differ from each other by at most 2, such as with {3, 4, 5} or {3, 5, 5}.
Examples
scoresClump([3, 4, 5]) → true
scoresClump([3, 4, 6]) → false
scoresClump([1, 3, 5, 5]) → true
A solution below here seems to work but Translating it into Python looks tricky.
function scoresClump(scores) {
for (let i = 0; i < scores.length - 1; i++) {
if (scores[i + 2] - scores[i] <= 2) {
return true;
}
}
return false;
}
I have tried this in Python and it keeps going out of range or giving the wrong output.
arr=[1,3, 5, 5]
i=0
while i<(len(arr)-1):
if (arr[i+2]-arr[i])<=2 and (arr[i+1]-arr[i])<=2:
print("True")
i=i+1
else:
print("False")
break
You're iterating until i < len(arr)-1, but you're reaching for arr[i+2], which is out of range.
In Python you usually do not need to use an index variable. As you've seen they're a source of errors, and Python offers cleaner syntax without using them. For instance:
# unpythonic
for i in range(len(scores)):
print(scores[i])
# pythonic
for score in scores:
print(score)
zip combines two (or more) things you can iterate over.
scores[2:] means "the scores list, but discarding the first two values".
scores = [1, 2, 3, 4, 5, 6]
for a, b in zip(scores, scores[2:]):
print(a, b)
# 1 3
# 2 4
# 3 6
# zip then ends because it reached the end of scores[2:]
So, you can use zip and list slicing to compare the list with itself without index variables:
def scores_clump(scores):
for a, b in zip(scores, scores[2:]):
if b - a <= 2:
return True
return False
scores_clump([1, 3, 4, 5])
# 4 - 1 is not <= 2
# 5 - 3 is <= 2, return True
scores_clump([1, 3, 6, 7, 9])
# 6 - 1 is not <= 2
# 7 - 3 is not <= 2
# 9 - 6 is not <= 2
# reached end of loop with no match, return False
scores_clump([3, 3, 7, 7, 9])
# 7 - 3 is not <= 2
# 7 - 3 is not <= 2
# 9 - 7 is <= 2, return True
Taking a leaf from Max's answer, you can reduce it further using any:
def scores_clump(scores):
return any(b - a <= 2 for a, b in zip(scores, scores[2:]))
You can use this following function -
def scoresClump(nums):
for x in range(2, len(nums)):
if nums[x] - nums[x-2] <= 2:
return True
return False
if you want a one-liner using any() -
def scoresClump(nums):
return any(nums[x] - nums[x-2] <= 2 for x in range(2, len(nums)))
>>> scoresClump([3, 4, 5])
True
>>> scoresClump([3, 4, 6])
False
>>> scoresClump([3, 4, 5, 5])
True
>>> scoresClump([3, 4])
False
>>> scoresClump([3])
False
>>> scoresClump([3, 3, 7, 7, 9])
True
Your if statement will reach arr[:-1] and then try and check two elements ahead of that, which don't exist, therefore going out of range. Rather than a while loop I would try something like this:
for x in range(0, len(arr)-2)
This is basically a "sliding window" problem where window size=3 and we keep iterating over the array until we find a window where difference between adjacent elements is less than or equal to 2.
Here we can simply check if difference between last and first element of the window is <=2 or not because we are given a sorted array.
def scoresClump(array):
for i in range(2,len(array)):
if array[i]-array[i-2]<=2:
return True
return False
print(scoresClump([1, 3, 5, 5]))
I'd like to sum the first element and last elements of a list, and then exclude those two numbers and repeat that process again until there is only one element in the list. Like this:
[5,4,3,2,1,6]
[11,5,5]
[16,5]
[21]
I used some methods but didn't work.
I am just a computer science student starting to python so help me out please guys.
Thank you.
Main logic of this answer is revolve around len of last list print. Lets break it in few points :
LOGIC :
1. Basically we need sum of first-ith and last-ith value for that we used this code:
l_u[-1][i] + l_u[-1][-i - 1]
2. Above point is only valid when lenght of last append list is even for odd-length we have to append this only at even poistion :
l_u[-1][i]
3. Among above two statement which is going to true this is done by this condition:
len(l_u[-1])%2 != 0 and i%2 != 0
CODE :
l = [5, 4, 3, 2, 1, 6]
l_u = [l]
condn = True
j = 0
while condn:
l_u.append([
l_u[-1][i] if len(l_u[-1]) % 2 != 0 and i % 2 != 0 else l_u[-1][i] +
l_u[-1][-i - 1] for i in range(
len(l_u[-1]) // 2 if len(l_u[-1]) % 2 == 0 else len(l_u[-1]) // 2 +
1)
])
if len(l_u[-1]) <= 1:
break
print(l_u)
OUTPUT :
[[5, 4, 3, 2, 1, 6], [11, 5, 5], [16, 5], [21]]
I'm working on a validator of credit cards. That sphere is new for me, so please, don't laugh:D
I'm trying to finish it without any libraries.
def creditCardValidation(creditcard):
creditcard = creditcard.replace( ' ', '' )
creditcard = [int(i) for i in creditcard]
evens = creditcard[::2]
odds = creditcard[1::2]
evens = [element * 2 for element in evens]
for j in evens:
if j >= 10:
j = [int(d) for d in str(j)]
for x in j:
evens.append(x)
for j in evens:
if j >= 10:
evens.remove(j)
return ((sum(evens) + sum(odds)) % 10 == 0)
creditCardValidation('1234 5678 9101 1213')
creditCardValidation('4561 2612 1234 5464')
creditCardValidation('4561 2612 1234 5467')
So the problem is in the array evens.
It returns
[2, 6, 14, 0, 2, 2, 1, 0, 1, 4, 1, 8]
[8, 4, 2, 2, 6, 12, 1, 2, 1, 0, 1, 2]
[8, 4, 2, 2, 6, 12, 1, 2, 1, 0, 1, 2]
It should return the same results except those which greater than 10. Everything works fine. Take a look at the first array, 18 deleted as well as 10, but 14 is not.
Removing while iterating over the array is not the best thing to do and will mostly result in skipping some elements in the array while iterating, so a safer way to do this
for j in evens:
if j >= 10:
evens.remove(j)
is to collect all the elements you want to remove in another list then subtract it from your original if you are using numpy arrrays or removing them one by one, as python lists has no subtraction operation defined to subtract one array from a another
to_remove = []
for j in evens:
if j >= 10:
to_remove.append(j)
for j in to_remove:
events.remove(j)
or you could whitelist instead of blacklisting
small_evens = []
for j in evens:
if j < 10:
small_evens.append(j)
# use small_evens and discard evens array
A couple of issues:
Python has zero indexed arrays, so evens[::2] is actually returning the first, third, etc. digit. Luhn's algo requires even digits (assuming 1 indexing) to be doubled.
You shouldn't modify a list you are iterating over.
You can simplify, removing a lot of the list creations:
def creditCardValidation(creditcard):
*creditcard, checkdigit = creditcard.replace(' ', '')
total = 0
for i, digit in enumerate(map(int, creditcard), 1):
if i % 2 == 0:
digit *= 2
total += digit // 10 # Will be zero for single digits
total += digit % 10
return 9*total % 10 == int(checkdigit)
In []:
creditCardValidation('1234 5678 9101 1213')
Out[]:
True
In []:
creditCardValidation('4561 2612 1234 5464')
Out[]:
False
I'm trying to add two lists. If the last variable is greater than 10, it needs to carry over to the previous variable in the list. For example :
1 / 2 / 3 (List 1)
7 / 8 / 9 (List 2)
Should equal
9 / 1 / 2 not 8/10/12
So far, I have
list1 = [1, 2, 3]
list2 = [7, 8, 9]
SumOfLists = [x+y for x,y in zip(list1, list2)]
That adds the lists together, but I'm not sure how to make the number carry over.
You can try this code.
list1 = [1, 2, 3]
list2 = [7, 8, 9]
def add_list(a,b):
carry = 0
res_list = []
for i,j in zip(a[::-1],b[::-1]): # Iterate through the lists in reverse
val = (i+j+carry)%10 # Store the sum in val
carry = (i+j+carry)//10 # Store the carry
res_list.append(val) # Append to the returning list
return res_list[::-1] # Return the list
print add_list(list1,list2)
Wil print
[9, 1, 2]
Algorithm
Loop through each of the values in reverse. Add each corresponding values. If the values are above 10 then find the exceeding value and put it to carry. Finally return the reverse of the list.
list1 = [1, 2, 3]
list2 = [7, 8, 9]
cur = 0 # num to carry over
result = []
for x,y in zip(reversed(list2),reversed(list1)):
if x + y + cur > 10: # if sum greater than 10, remember to add 1 on
t = x+y + cur # the next loop
d = str(t)[1] # get the rightmost digit
result.append(int(d))
cur = 1
else: # nothing to curry over, but still add cur,
# it may be 1
result.append(x+y+cur)
cur = 0
print(list(reversed(result)) )
[9, 1, 2]
just subtract 10 if it's more then 10 and add 1 to it's previous element. Do this proccess for all element in sum list
if SumOfLists[2] >= 10:
SumOfLists[2] -= 10
SumOfLists[1] += 1
And at last check
if SumOfLists[0] >= 10:
for i in range(len(SumOfLists)-1,0,-1):
SumOfLists[i] = SumOfLists[i-1]
SumOfLists[0] = 1