Sum of lowest numbers that are part of an arithmetic sequence - python

I would like to iterate through a list of integers, calculate the sum of the lowest numbers that belongs to an arithmetic sequence with common difference 1 + the numbers that are not part of a sequence:
mylist = [2,3,4,10,12,13]
So, from mylist it would be 2 (from 2,3,4) + 10 (not part of a sequence) + 12 (from 12,13)
I've managed to make something work, but I could only figure out how to do it, if the list is reversed. And I am sure there is a better/cleaner solution that mine:
mylist = [13,12,10,4,3,2]
result = mylist[-1] #if I don't do this, I don't know how to grab the last item in the list
for i in range(len(mylist)-1):
if mylist[i] - mylist[i+1] == 1:
continue
else:
result += mylist[i]
Hope someone will help me out, and that I get a little wiser in my coding journey. Thanks.

#KennethRasch - earlier post would work. Alternatively, you can do this as well:
Try to find each possible subsequence's starting numbers as starts then just sum them to get answer.
L = [13,12,10,4,3,2]
L.sort()
starts = [x for x in L if x-1 not in L]
print(starts)
result = sum(starts)
print(result) # 24
Alternatively, you can put this into a function for future re-use it:
def sum_lowests(L):
'''L is a numbers sequence '''
L.sort()
starts = [x for x in L if x-1 not in L]
#ans = sum(starts) # can skip this step; just to make it clear
return sum(starts)
if __name__ == '__main__':
L = [13,12,10,4,3,2]
A = [1, 2, 3, 5,6, 9,10,11, 16]
print(sum_lowests(L))
print(sum_lowests(A)) # 31

Keep a running sum, a running index, and iterate while it's still a sequence:
mylist = [13,12,10,4,3,2]
mylist.sort() # this way sequences will be contiguous in the list
cur_index = 0
cur_sum = 0
while cur_index < len(mylist):
# add the current element to the sum
cur_sum += mylist[cur_index]
# now iterate through while it's a contiguous sequence
cur_index += 1
while cur_index < len(mylist) and mylist[cur_index] == mylist[cur_index - 1] + 1:
cur_index += 1
print(cur_sum)

Related

Minimum count to sort an array in Python by sending the element to the end

Here is the explanation of what I'm trying to say:-
Input:- 5 1 3 2 7
Output:- 3
Explanation:
In first move, we move 3 to the end. Our list becomes 5,1,2,7,3
In second move, we move 5 to the end. Our list becomes 1,2,7,3,5
In third move, we move 7 to the end. Our final list = 1,2,3,5,7
So, total moves are:- 3.
Here is what I tried to do, but failed.
a = [int(i) for i in input().split()]
count = 0
n = 0
while (n < len(a) - 1):
for i in range(0,n+1):
while (a[i] > a[i + 1]):
temp = a[i]
a.pop(i)
a.append(temp)
count += 1
n += 1
print(count, end='')
I'd like to request your assistance in helping in solving this question.
jdehesa's answer is basically right, but not optimal for cases, when there is more element of same value. Maybe more complex solution?
def min_moves(a):
c = 0
while(1):
tmp = None
for i in range(0, len(a)):
if a[i] != min(a[i:]) and (tmp is None or a[i] < a[tmp]):
tmp = i
if tmp is None:
return c
else:
a.append(a.pop(tmp))
c += 1
Edit:
Or if you don't need ordered list, there's much more easier solution just to count items that are out of order for the reason from jdehesa's solution :-D
def min_moves(a):
c = 0
for i in range(0, len(a)):
if a[i] != min(a[i:]):
c += 1
return c
Edit 2:
Or if you like jdehesa's answer more, small fix is to reduce lst to set, so it will get smallest index
sorted_index = {elem: i for i, elem in enumerate(sorted(set(lst)))}
I cannot comment yet.
I don't know if it can be done better, but I think the following algorithm gives the right answer:
def num_move_end_sort(lst):
# dict that maps each list element to its index in the sorted list
sorted_index = {elem: i for i, elem in enumerate(sorted(lst))}
moves = 0
for idx, elem in enumerate(lst):
if idx != sorted_index[elem] + moves:
moves += 1
return moves
print(num_move_end_sort([5, 1, 3, 2, 7]))
# 3
The idea is as follows. Each element of the list would have to be moved to the end at most once (it should be easy to see that a solution that moves the same element to the end more than once can be simplified). So each element in the list may or may not need to be moved once to the end. If an element does not need to be moved is because it ended up in the right position after all the moves. So, if an element is currently at position i and should end up in position j, then the element will not need to be moved if the number of previous elements that need to be moved, n, satisfies j == i + n (because, after those n moves, the element will indeed be at position j).
So in order to compute that, I sorted the list and took the indices of each element in the sorted list. Then you just count the number of elements that are not in the right position.
Note this algorithm does not tell you the actual sequence of steps you would need to take (the order in which the elements would have to be moved), only the count. The complexity is O(n·log(n)) (due to the sorting).
I think you can simplify your problem,
Counting elements that need to be pushed at the end is equivalent to counting the length of the elements that are not in sorted order.
l = [5, 1, 3, 2, 7]
sorted_l = sorted(l)
current_element = sorted_l[0]
current_index = 0
ans = 0
for element in l:
if current_element == element:
current_index += 1
if current_index < len(l):
current_element = sorted_l[current_index]
else:
ans += 1
print(ans)
Here the answer is 3

Using a loop to describe multiple conditions

In the following code, I am trying to extract numbers from a list in which all digits are divisible by 2. The following code works.
l = range(100,401)
n=[]
for i in l:
s =str(i)
if all([int(s[0])%2==0,int(s[1])%2==0,int(s[2])%2==0]):
n.append(s)
print(",".join(n))
I was trying to insert a for loop to avoid writing all three conditions explicitly.
l = range(100,401)
n=[]
ss=[]
for i in l:
s =str(i)
ss.append(s)
for element in ss:
for j in range(3):
if int(element[j])%2==0:
n.append(element)
print(n)
I can't get the desired output. Not only that, the elements of output list 'n' at even index are printed twice. I am unable to figure out WHY?
Thanks.
Generator expression checking if all() elements evaluate to True comes to your rescue:
l = range(100,401)
n=[]
for i in l:
s = str(i)
if all(int(ch) % 2 == 0 for ch in s):
n.append(s)
print(",".join(n))
Now it also works even if you work with more digits.
Thanks for #jpp's advice on generator expression!
And here a faster alternative where you evaluate if any() is not divisable with 2.
l = range(100,401)
n=[]
for i in l:
s = str(i)
if any(int(ch) % 2 != 0 for ch in s):
continue
else:
n.append(s)
print(",".join(n))
You can do this:
l = range(100, 401)
n = []
for i in l:
v = 0
for j in str(i):
if int(j) % 2 == 0:
v += 1
if v == len(str(i)):
n.append(str(i))
print(",".join(n))
Or with some list comprehension:
l = range(100, 401)
n = []
for i in l:
if all(int(j) % 2 == 0 for j in str(i)):
n.append(str(i))
print(",".join(n))
Or with even more list comprehension:
l = range(100, 401)
n = [str(i) for i in l if all(int(j) % 2 == 0 for j in str(i))]
print(",".join(n))
Or with a ridiculous minimizing:
print(",".join([str(i) for i in range(100, 401) if all(int(j) % 2 == 0 for j in str(i))]))
Explaining
OP asked me to explain why his code doesn't work. I'll make it in some steps, also optimizing it:
l = range(100,401)
n = []
ss = []
for i in l: # You don't need this loop, you are just making a new list with string values instead of integers. You could make that on the fly.
s = str(i)
ss.append(s)
for element in ss:
for j in range(3):
if int(element[j]) % 2 == 0: # This only check if the current digit is pair and it append the whole number to the list. You have to check if the 3 numbers are pair AND then append it.
n.append(element)
print(n)
Your code check each digit and if that is true, the number is appended to the result list (n). But you don't want that, you want to check if the 3 digits that make the number are pair, so you have to check the whole group.
For example you could do this:
for element in l:
pairs = 0
for j in range(3):
if int(str(element)[j]) % 2 == 0:
pairs += 1 # Each time a digit of the number is pair, `pairs` variable increase in one
if pairs == 3: # If the 3 digits are true it append your number
n.append(str(element))
That is my first idea of how to improve your code, but instead of element and pairs I use j and v, (also I don't use range(3), I just iterate over the stringed number).
If you are looking for something "better" you could try to use a list comprehension like all(int(j) % 2 == 0 for j in str(i)). That iterate over all the digits to check if the are pair, if all the checks are true (like 222, or 284) it returns true.
Let me know if I should explain something more.
Try this method. You don't need to check all the numbers.
You just need to change the range statement from range(100, 401) to range (100, 401, 2) and add some checks as the Numbers which have first digit as Odd you can skip all the 100 numbers and then in next 10 series you can skip 10 if the tenth digit is odd. It reduces the complexity and decreases your processing time.
l = range(100, 401, 2)
n = []
for i in l:
s = str(i)
if int(s[0]) % 2 == 1:
remainder = i % 100
i = i - remainder + 100 - 1
continue
elif int(s[1])%2 == 1:
remainder = i % 10
i = i - remainder + 10 - 1
continue
n.append(s)
print(",".join(n))

Insertion sort doesn't sort

I have attempted to create an insertion sort in python, however the list returned is not sorted. What is the problem with my code?
Argument given: [3, 2, 1, 4, 5, 8, 7, 9, 6]
Result: 2
1
3
6
4
7
5
8
9
Python code:
def insertion_sort(mylist):
sorted_list = []
for i in mylist:
posfound = 0 #defaults to 0
for j in range(len(sorted_list)):
if sorted_list[j] > i:
sorted_list.insert(j-1, i) #put the number in before element 'j'
posfound = 1 #if you found the correct position in the list set to 1
break
if posfound == 0: #if you can't find a place in the list
sorted_list.insert(len(sorted_list), i) #put number at the end of the list
return sorted_list
You need to change sorted_list.insert(j-1, i) to be sorted_list.insert(j, i) to insert before position j.
insert(j-1, ..) will insert before the previous element, and in the case where j=0 it'll wrap around and insert before the last element.
The Python data structures tutorial may be useful.
As Efferalgan & tzaman have mentioned your core problem is due to an off-by-one error. To catch these sorts of errors it's useful to print i, j and sorted_list on each loop iteration to make sure they contain what you think they contain.
Here are a few versions of your algorithm. First, a repaired version of your code that fixes the off-by-one error; it also implements Efferalgan's suggestion of using .append if an insertion position isn't found.
def insertion_sort(mylist):
sorted_list = []
for i in mylist:
posfound = 0 #defaults to 0
for j in range(len(sorted_list)):
if sorted_list[j] > i:
sorted_list.insert(j, i) #put the number in before element 'j'
posfound = 1 #if you found the correct position in the list set to 1
break
if posfound == 0: #if you can't find a place in the list
sorted_list.append(i) #put number at the end of the list
return sorted_list
Here's a slightly improved version that uses an else clause on the loop instead of the posfound flag; it also uses slice assignment to do the insertion.
def insertion_sort(mylist):
sorted_list = []
for i in mylist:
for j in range(len(sorted_list)):
if sorted_list[j] > i:
sorted_list[j:j] = [i]
break
else: #if you can't find a place in the list
sorted_list.append(i) #put number at the end of the list
return sorted_list
Finally, a version that uses enumerate to get the indices and items in sorted_list rather than a simple range loop.
def insertion_sort(mylist):
sorted_list = []
for u in mylist:
for j, v in enumerate(sorted_list):
if v > u:
sorted_list[j:j] = [u]
break
else: #if you can't find a place in the list
sorted_list.append(u) #put number at the end of the list
return sorted_list
As often, it was a off-by-one error, the code below is fixed. I also made some parts a bit prettier.
def insertion_sort(mylist):
sorted_list = []
for i in mylist:
for index, j in enumerate(sorted_list):
if j > i:
sorted_list.insert(index, i) #put the number in before element 'j'
break
else:
sorted_list.append(i) #put number at the end of the list
return sorted_list

How to remove a number in a list if it equals 0. Python

I'm adding two lists together, and if the sum of one of the added elements = 0, I must remove it from the list. The numbers have to carry over if they hit over 10. So far this is what I've gotten:
list = [1,2,1]
list2 = [2,18,9]
SumOfLists = [x+y for x,y in zip (list, list2)]
if SumOfLists[2] >= 10:
SumOfLists[2] -= 10
SumOfLists[1] += 1
if SumOfLists[1] >= 10:
SumOfLists[1] -= 10
SumOfLists[0] +=1
if SumOfLists[0,1,2] == 0:
return SumOfLists[0,1,2] != 0
The last part doesnt work. How do I fix this, and have them print out with '/' in between, and not as [1,2,3]
You could use a list comprehension with a condition to get rid of the 0, and then join on the '/' character:
mylist = [1,3,0,5]
result = '/'.join([str(x) for x in mylist if x != 0])
new_list = [str(n) for n in old_list if n]
print '/'.join(new_list)

Counting evens in a two-dimensional list?

Hey guys I'm trying to make a program that counts the evens in a two-dimensional list. The program I made so far is not returning what I want it to.
def Evens(x):
count = 0
x = len(x)
for a in range(x):
if a%2 == 0:
count = count + 1
return count
that keeps returning 2 for the list Evens([[1,3],[1,9,7,1,3],[13]]) when I want it to return 4. I tried everything but it seems to not be working correctly.
Thanks
The problem you're encountering is that you are checking the indices to see if they are even, not the values. You're also not checking in the sublists.
More straightforward, IMO, is to do this:
import itertools
def evens(x):
return sum(a % 2 == 0 for a in itertools.chain.from_iterable(x))
You need to actually iterate over the sublists.
def evens(l):
count = 0
for l2 in l:
for i in l2:
if i%2 == 0:
count += 1
return count
Or you can you can take a much simpler approach.
def evens(l):
return sum(i%2==0 for l2 in l for i in l2)
The second approach uses the fact that in an integer context, True == 1 and False == 0, so you would get the expected result.
You need to iterate over all the sublists:
In [34]: l = [[1,4,3],[12,0,7,10,3],[13]]
In [35]: sum(n%2 == 0 for sub in l for n in sub)
Out[35]: 4
You need to iterate over the elements in each sublist as well:
def count_evens(l):
total = 0
for l2 in l:
for item in l2:
if item % 2 == 0:
total += 1
return total
What you were doing before was iterating over the number of sublists (i.e. [0, 1, 2, 3] for a list with 4 elements). Your code was working, but it wasn't working properly.

Categories

Resources