Trying to understand how my python code works - python

i = [1, 2, 3, 5, 5, 7, 9, 12, 14, 14,]
list_length = len(i)
def numbers_found(x):
y = i.count(x)
return y
latest_num = i[list_length - 1]
for z in range(latest_num + 1):
print("Found", numbers_found(z), "of number", "\"" + str(z) + "\".")
I am trying to find how many of a certain number is available in the list, if I somehow minus by 1 to the maximum number in the list (assuming it is in ascending order) and add 1 again it works. Please help explain this to me.

Lets break it down, step by step.
# a list. indexes shown below
# 0 1 2 3 4 5 6 7 8 9
i = [1, 2, 3, 5, 5, 7, 9, 12, 14, 14]
# getting the length of the list (10)
# or the number of elements
list_length = len(i)
# a function returning the amounts of
# times a passed value is found in the list i
def numbers_found(x):
y = i.count(x)
return y
# see above that list_length is 10
# but we need one less that to retrieve the last element
# which will be 14
latest_num = i[list_length - 1]
# range given 1 argument iterates from 0
# to the number you pass it but not including it
# since latest_num is 14, it won't include it
# So range(15) would iterate like
# 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
for z in range(latest_num + 1):
print("Found", numbers_found(z), "of number", "\"" + str(z) + "\".")
The reason range works like this, is it's common to see range(length_of_my_list) and expect it to return indexes for the full list.
In order for that to happen you need to only iterate to and not include the length. In your case (10).
What you are using it for is something else. You are trying to find the occurrences of all the numbers in the list. Since you are not using it for indexes, adding + 1 works since you WANT it to include 14.

Use
for z in range(len(i)):
print("Found", numbers_found(z), "of number", "\"" + str(z) + "\".")
Here len(i) is the size of i i.e. the number of elements in i, and range(n) = [0, 1, ..., n - 1] i.e all numbers from 0 to n-1, sorted asc.

Related

How to return the turn of an element in a list?

I want to know if an element is in the list multiple times and if so what is the order of the 2nd one. The 2nd one is important, not the 3rd or the 4th one.
list = [1, 3, 4, 2, 0, 1, 6, 7, 0]
My expected output is:
"1" is in list 2 times and the order of the 2nd "1" is six.
Doing it with one pass over the list, while saving the indexes of the target number and checking their amount in the end:
l = [1, 3, 4, 2, 0, 1, 6, 7, 0]
target = 1
idxs = []
for i, num in enumerate(l):
if num == target:
idxs.append(i)
if len(idxs) > 1:
print(f'"{target}" is in the list {len(idxs)} times and the order of the 2nd "{target}" is {idxs[1]+1}')
else:
print(f'{target} is in the list 0 or 1 times')
The indexes can also be obtained with a neat list-comprehension:
idxs = [i for i, num in enumerate(l) if num == target]
Pretty rough code, just to convey the logic you can apply to get it done:
list = [1, 3, 4, 2, 0, 1, 6, 1, 7, 0]
flagged = []
for index, elem in enumerate(list):
elem_count = list[index:].count(elem)
if elem_count > 1 and elem not in flagged:
flagged.append(elem)
temp_index = list[index + 1:].index(elem)
actual_index = index + temp_index + 1
print(str(elem) + ' is in the list ' + str(elem_count) + ' times and the order of 2nd is ' + str(actual_index))
# OP
# 1 is in the list 3 times and the order of 2nd is 5
# 0 is in the list 2 times and the order of 2nd is 9
Are you sure it's 6 and not 5? Indexing starts from 0.
In any case, you can use index for finding it:
first_idx = list.index(element)
print(list.index(element, first_idx + 1))
Like that you will find the first occurrence of the element and than return the index of the second one. If you want it 6 and not 5 - increment it by 1.

Swapping opposite elements of a List of Integers if either is Odd

Write a program with the definition of a function named Array_Swap() that will accept an integer list & its size as arguments and the function will swap elements in such a way that the first element is swapped with the last element, the second element is swapped with the second last element and so on, only if anyone or both the elements are odd and display the result.
If initially, a list of seven elements is: [5, 16, 4, 7, 19, 8, 2], the contents of the list after the execution should be:
[2, 16, 19, 7, 4, 8, 5].
def Array_Swap(List,Size):
for i in range (Size//2):
List[i]=List[Size//2-i]
print(List)
L=[]
n=int(input("Enter number of elements"))
for i in range(n):
x=int(input("Enter element"))
L.append(x)
Array_Swap(L,len(L))
The size/length of the list is not relevant because it can be obtained by len(list). And even then it's not required to conditionally swap items in the list. I suggest that the Size parameter be removed, but considering it's an assignment, it can be given a default of None so that it can be ignored by the caller if desired.
The following algorithm zips the input list with its reverse to form pairs relative to their index from the front and end of the list respectively, i.e. the first and last items are paired, the second and second last are paired, etc. Once the items are paired it is simply a matter of iterating over the list and emitting the second number of the pair if either number is odd, or the first number if neither is odd - effectively swapping the pairs as required.
This is done in-place (that's what the List[:] does) with a list comprehension.
def ArraySwap(List, Size=None):
List[:] = [b if (a % 2 or b % 2) else a
for a, b in zip(List, reversed(List))]
print(List)
>>> l = [5, 16, 4, 7, 19, 8, 2]
>>> ArraySwap(l)
[2, 16, 19, 7, 4, 8, 5]
>>> l
[2, 16, 19, 7, 4, 8, 5]
>>> l = list(range(1,30))
>>> ArraySwap(l)
[29, 2, 27, 4, 25, 6, 23, 8, 21, 10, 19, 12, 17, 14, 15, 16, 13, 18, 11, 20, 9, 22, 7, 24, 5, 26, 3, 28, 1]
>>> ArraySwap([1])
[1]
>>> ArraySwap([])
[]
To swap two elements in the list, use the pattern a, b = b, a.
If i is the index of a list item, it's opposite/mirror element is -(i+1), or - i - 1.
so for the 0th element (first one), the mirror is -(0+1), = -1
using that as the indexer for the element, swap the two list elements IF
check that at least one of them is odd before swapping:
def Array_Swap(List,Size):
for i in range (Size // 2):
if List[i] % 2 == 1 or List[-(i+1)] % 2 == 1:
List[i], List[-(i+1)] = List[-(i+1)], List[i]
print(List)
L = [5, 16, 4, 7, 19, 8, 2] # use your input blocks as before, this is an example
Array_Swap(L,len(L))
Output: [2, 16, 19, 7, 4, 8, 5]
(And if L = [5, 16, 4, 7, 19, 8, 1, 2], output is [2, 1, 4, 19, 7, 8, 16, 5].)
Btw, you don't need to pass in the size of the list as a parameter.
You could do just: for i in range(len(List) // 2)
Another solution:
def Array_Swap(List, Size=None):
if Size is None:
Size = len(List)
for (i, j) in zip(range(Size // 2), range(Size - 1, Size // 2, -1)):
if List[i] % 2 or List[j] % 2:
List[i], List[j] = List[j], List[i]
print(List)
Alternatively:
Size parameter is redundant since python's list instance knows its own size
Use bitwise operatos & | >>... possibly cheaper than modulus % and divide / operations.
def Array_Swap(List):
for i in range(len(List) >> 1):
if (List[i] | List[-i-1]) & 1:
List[i], List[-i-1] = List[-i-1], List[i]
print(List)
The standard way to swap two variables in Python is:
a, b = b, a
In this case, you would do:
lst[i], lst[size - i - 1] = lst[size - i - 1], lst[i]
which swaps the ith element with the element that is at index size - i - 1 (i.e. the ith index from the end).
The other issue with your code is that it doesn't check whether either of the elements being swapped are odd, which you can resolve by adding the condition:
if lst[i] % 2 or lst[size - i - 1] % 2:
before doing the swap. This uses the modulo operator (%) to check the parity of the elements. Taking a number modulo 2 will return 1 if the number is odd. If either are odd (1 has a truth value of True), the condition would succeed and the swap will be performed.
Finally, your function was printing the list, rather than returning it. Its usually best to return a result and print the returned result.
The full working version, with the above three changes is as follows:
def list_swap(lst, size):
for i in range(size // 2):
if lst[i] % 2 or lst[size - i - 1] % 2:
lst[i], lst[size - i - 1] = lst[size - i - 1], lst[i]
return lst
l = []
n = int(input("Enter number of elements: "))
for _ in range(n):
x = int(input("Enter element: "))
l.append(x)
result = list_swap(l, len(l))
print(result)
Also note, I've changed all the variables to be lowercase, which is standard in Python.
With your shown example:
Enter number of elements: 7
Enter element: 5
Enter element: 16
Enter element: 4
Enter element: 7
Enter element: 19
Enter element: 8
Enter element: 2
[2, 16, 19, 7, 4, 8, 5]

Add 1 for odd numbers on list Python

So this is my code:
numbers = []#1
for i in range(10):
i += 1
numbers.append(i)
print (numbers)
numbers2 = [n + 2 for n in numbers]#2
print (numbers2)
numbers3 = []#3
for x in numbers2:
if (x % 2 == 1) :
x += 1
numbers3 = x
print (numbers3)
I'm using Google Colab and run those codes on 3 separate code cells(hashtag numbers comment). The #1 program output is [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]. And the #2 output is [3, 4, 5, 6, 7, 8, 9, 10, 11, 12]. So at #3 cell I want program to add 1 on each odd numbers in numbers2 list. The output I want is [4, 4, 6, 6, 8, 8, 10, 10, 12, 12]. But what I get is :
4
6
8
10
12
Also I'm trying to not use function(just for these codes). And for loop on #1 code I intend to do that.
Additional question : Is it possible to modify elements on list without append the result to another list(like #2 code)? Like just add 2 on each numbers on list
Try the following:
second_list = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
third_list = second_list
for i in range(len(second_list)):
if (second_list[i] % 2 == 1):
make_even = second_list[i] + 1
third_list[i] = make_even
else:
third_list[i] = second_list[i]
print (third_list)
You'll have to tweak it for the Google Colab project you're doing, but the logic here should be right. Right now this answer works in regular Python 3.
your third cell should look like this, you were close to the solution all you need to do is to add x values in numbers3 list
numbers3 = []#3
for x in numbers2:
if (x % 2 == 1) :
x += 1
numbers3.append(x)
print(numbers3)
In order to fill the list instead of just printing the value you must use the append function instead of =
numbers3 = x
#becomes
numbers3.append(x)
To get the list in the format you want, you also have to drop the append out of the if statement, and drop the print out of the for loop, like so:
numbers3 = []#3
for x in numbers2:
if (x % 2 == 1) :
x += 1
numbers3.append(x) # Here
print (numbers3) # and here

Packing a small number of packages into a fixed number of bins

I have a list of package sizes. There will be a maximum of around 5 different sizes and they may occur a few times (<50).
packages = [5,5,5,5,5,5,10,11]
I need to pack them into a fixed number of bins, for example 3.
number_of_bins = 3
The bins may vary in size (sum of the sizes of the packed packages) between 0 and, say, 2 (that is, the difference of the sum of the sizes of the packages in the bins must be equal or nearly equal). So having bins with [1,2] (=3) and [2] (=2) (difference is 1) is fine, having them with [10] (=10) and [5] (=5) (difference is 5) is not.
It is possible not to sort all packages into the bins, but I want the solution where a minimum number of packages remains unpacked.
So the best solution in this case (I think) would be
bins = [11,5],[10,5],[5,5,5]
remaining = [5]
There's probably a knapsack or bin-packing algorithm to do this, but I haven't found it. I'm fine with brute-forcing it, but I'm not sure what's an efficient way to do that.
Is there any efficient way of doing this easily? Did I just miss the relevant search term to find it?
Another example:
packages = [5,10,12]
number_of_bins = 2
leads to
bins = [12],[10]
remaining = [5]
because
bins = [12],[10,5]
has bin sizes of 12 and 15 which vary by more than 2.
Analog:
packages = [2,10,12]
number_of_bins = 3
leads to
bins = [2],[],[]
remaining = [12,10]
Here is a solution using pulp:
from pulp import *
packages = [18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 65, 65, 65]
number_of_bins = 3
bins = range(1, number_of_bins + 1)
items = range(0, len(packages))
x = LpVariable.dicts('x',[(i,b) for i in items for b in bins],0,1,LpBinary)
y = LpVariable('y', 0, 2, LpInteger)
prob=LpProblem("bin_packing",LpMinimize)
#maximize items placed in bins
prob.setObjective(LpAffineExpression([(x[i,b], -3) for i in items for b in bins] + [(y, 1)]))
#every item is placed in at most 1 bin
for i in items:
prob+= lpSum([x[i,b] for b in bins]) <= 1
for b in bins:
if b != 1: # bin 1 is the one with lowest sum
prob+= LpAffineExpression([(x[i,b], packages[i]) for i in items] + [(x[i,1], -packages[i]) for i in items]) >= 0
if b != number_of_bins: # last bin is the one with highest
prob+= LpAffineExpression([(x[i,number_of_bins], packages[i]) for i in items] + [(x[i,b], -packages[i]) for i in items]) >= 0
#highest sum - lowest sum <= 2 so every difference of bin sums must be under 2
prob += LpAffineExpression([(x[i,number_of_bins], packages[i]) for i in items] + [(x[i,1], -packages[i]) for i in items]) <= 2
prob += LpAffineExpression([(x[i,number_of_bins], packages[i]) for i in items] + [(x[i,1], -packages[i]) for i in items]) == y
prob.solve()
print(LpStatus[prob.status])
for b in bins:
print(b,':',', '.join([str(packages[i]) for i in items if value(x[i,b]) !=0 ]))
print('left out: ', ', '.join([str(packages[i]) for i in items if sum(value(x[i,b]) for b in bins) ==0 ]))
Tricky one, really not sure about an optimal solution. Below is a solution that just iterates all possible groups and halts at the first solution. This should be a minimal-remainder solution since we first iterate through all solutions without any remainder.
It also iterates over solutions as everything in the first bin, which could be excluded for a faster result.
import numpy as np
def int_to_base_list(x, base, length):
""" create a list of length length that expresses a base-10 integer
e.g. binary: int2list(101, 2, 10) returns array([0, 0, 0, 1, 1, 0, 0, 1, 0, 1])
"""
placeholder = np.array([0] * length) # will contain the actual answer
for i in reversed(range(length)):
# standard base mathematics, see http://www.oxfordmathcenter.com/drupal7/node/18
placeholder[i] = x % base
x //= base
return placeholder
def get_groups(packages, max_diff_sum, number_of_bins):
""" Get number_of_bins packaging groups that differ no more than max_diff_sum
e.g.
[5, 5, 5, 5, 5, 5, 10, 11] with 2, 3 gives [5,5,5], [10,5], [11,5]
[5, 10, 12] with 2, 2 gives [10], [12]
[2, 6, 12] with 2, 3 gives [2], [], []
We approach the problem by iterating over group indices, so the first
example above has solution [0 0 0 1 2 3 1 2] with the highest number being
the 'remainder' group.
"""
length = len(packages)
for i in range((number_of_bins + 1)**length - 1): # All possible arrangements in groups
index = int_to_base_list(i, number_of_bins + 1, length) # Get the corresponding indices
sums_of_bins = [np.sum(packages[index==ii]) for ii in range(number_of_bins)]
if max(sums_of_bins) - min(sums_of_bins) <= max_diff_sum: # the actual requirement
# print(index)
break
groups = [packages[index==ii] for ii in range(number_of_bins)]
# remainder = packages[index==number_of_bins+1]
return groups
On your examples:
packages = np.array([5, 5, 5, 5, 5, 5, 10, 11])
max_diff_sum = 2
number_of_bins = 3
get_groups(packages, max_diff_sum, number_of_bins)
>> [array([5, 5, 5]), array([ 5, 10]), array([ 5, 11])]
And
packages = np.array([5,10,12])
max_diff_sum = 2
number_of_bins = 2
get_groups(packages, max_diff_sum, number_of_bins)
>> [array([10]), array([12])]

I need to know why this is the output for these python condition

numbers=[i**3 for i in range (10) if i**3%3==1]
print(numbers)
#gets 1,64,343
Why is 1, 64, 343 the answer?
This is equivalent to the code:
for i in range(10):
if (i*i*i) % 3 == 1:
numbers.append(i*i*i)
print (numbers)
You are checking if the remainder obtained when the cube of a number from 1 to 10 is divided by 3 is equal to 1. If it is, you are adding it to a list and printing it.
The meaning of **
ex: 2**3= 2*2*2 #this means 2 to the power 3 = 8
The meaning of %
ex: 5%2= 1 #the sign means module, that means the remaining value after divide 5 by 2, it is one.
in your way, the correct path to write the for each is
for i in range(0,10):
value = i**3
if(value%3 == 1):
print("the value is {0}".format(value))
so the result is :
the value is 1
the value is 64
the value is 343
bit explanation inside the for loop
first get the i = 0, at this point value = 0*0*0 = 0, then value%3=0
then get the i=1, at this point value = 1*1*1 = 1 ,the 'value%3' means 1%3 = 1, so the answer i 1
.... like this see about other conditions also. hope this will help to you.
first i is in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
then if (i*i*i) rem 3 is equal to 1
it selects (i*i*i)
and for [1,4,7]: (1*1*1)%3==1, (4*4*4)%3==1 and (7*7*7)%3==1:
1*1*1=1 and 1/3=0 :remainder=1
4*4*4=64 and 64/3=21 :remainder=1
7*7*7=343 and 343/3=114 :remainder=1
so the output is:
[1*1*1, 4*4*4, 7*7*7] which is [1, 64, 343]
your code:
numbers=[i**3 for i in range (10) if i**3%3==1]
print(numbers)
and this code:
numbers=[]
for i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]:
if (i*i*i) % 3 == 1:
numbers.append(i*i*i)
print(numbers)
output this:
[1, 64, 343]

Categories