Python 3, Multiplication Table with 2D List using While Loops - python

I don't need an answer, just a jumping off point if possible.
I've made a multiplication table that prints 1-10, but my professor would like to see the table stored in a 2D list. I have my current code (working code, which is posted here), and new code I've made specifically for the "2D List" version, but I'm getting nowhere with either.
EDIT: I should probably clarify that the code is doing what I want it to do, which is outputting a multiplication table, but I am having trouble converting it into a 2D list.
#Initial list and global variables
MT = ["X", 1, 2, 3, 4, 5, 6, 7, 8, 9 ,10]
mult = 1
jump = 0
repeat = 1
list = 1
while repeat < 12:
index = 1
mult = 1
jump += 1
MT.append(MT[list])
while (index < 11):
MT.append(mult * jump)
mult += 1
index += 1
else:
repeat += 1
list += 1
else:
print("Multiplication Table:")
index = 0
while (index < 121):
if (((index + 1) % 11) != 0):
print(MT[index], end = "\t")
else:
print(MT[index], end = "\n")
index += 1

My first suggestion would be to start off with a 2D list:
MT = [["X", 1, 2, 3, 4, 5, 6, 7, 8, 9 ,10]]
rather than what you have.
Start a new empty list right before the inner while loop. You can initialize it with the first value new_row = [repeat]. Inside that loop append to the new_row rather than MT
After that while loop is done, you can append the new_row to MT
MT.append(new_row)
That should get you started with the 2d list. However, while I have you here...
If you need to repeat and keep track of how many times you've repeated, then use a for loop rather than a while loop.
For example, if you want a loop that goes from 2 to 12 you'd use:
for repeat in range(2, 13):
print(repeat)
Also, never overwrite built-in keywords as that can lead to unexpected behavior. So name list something else but I don't think that variable is really needed since it is similar to repeat.

Related

Infinite loop struggle for a beginner

I need to change the condition so that the loop is finite and list_ contains following values:
1 2 4 8 16 32 64
This is what I have in python, and I am struggling to understand what exactly needs to be changed and why.
list_ = []
i = 0
while i >= 0: # change the condition
list_.append(2 ** i)
i += 1
print(list_)
I suggest to use a for-loop instead of a while loop.
list_ = []
for i in range(7):
list_.append(2 ** i)
print(list_)
If you want to be very pythonic, then you can use a list comprehension:
list_ = [2 ** i for i in range(7)]
With a while a breaking condition is required (this implementation is to highlight the break)
out = []
i = 0
while True:
if i > 6:
break
out.append(2**i)
i += 1
print(out)
or with a list comprehension
print([2**i for i in range(6+1)])
Looks like you'll only need to switch the while condition in the loop. Rather than have a lower bound, you'll need to update with an upper bound - basically a "loop until" condition.
list_ = []
i = 0
while i <= 6: # change the condition
list_.append(2 ** i)
i += 1
print(list_). # [1, 2, 4, 8, 16, 32, 64]
But you can simplify this even further, with the help of a list comprehension. This is just a fancy (and bit more efficient) way of writing a for loop in python. Its more efficient because it doesn't need to call list.append within each loop iteration.
>>> [2 ** i for i in range(7)]
[1, 2, 4, 8, 16, 32, 64]
You could use while i <= 6: so that you while loop counts up to i=6.
However, I would recommend to use a for-loop with range(6) as a condition. So that your loop looks like the following:
for i in range(7):
…
This is just an alternative way, where i also counts up to the value of 6. using a for-loop would be good practice, as it saves you to declare i previously.

Unable to prevent 'list index out of range' error in fibonacci 'for' loop iteration

I'm still something of a beginner with Python and I was trying to optimise a function to generate the Fibonacci sequence to a specified number of values. This is the code I have written:
def attempt2(length):
listy=[]
for i in range(0,length+1):
if i == 0:
listy.append(1)
elif i == 1:
listy.append(1)
else:
listy.append(listy[i]+listy[i-1])
return listy
Whilst keeping this structure I have found no way to overcome the 'list index out of range' error. I think because the listy[i-1] would be out of range when i = 0, but if the function progresses through the loop linearly then the else statement should only take effect when i = 2. Can anyone see what I'm doing wrong?
Thanks!
So, to find out the source of your issue, we need to take a step back to see what your loop is doing.
Initially, your for-loop is counting from 0 to whatever the length is, let's see what the values for i will look like:
0
1
2
...
so starting from 2, since the behavior of 0,1 is defined:
listy.append(listy[2]+listy[1])
Remember that listy has 2 items now, which are zero indexed, in other words the items are 1 and 0, hence the item listy[2] doesn't exist.
Thus, your code should be
listy.append(listy[i-2]+listy[i-1])
It's not a good solution overall but the tiny mistake is that you should change line 9 to:
listy.append(listy[i - 1] + listy[i - 2])
Also you'll have a `length + 1` size list not `length`.
You are using wrong list indices
def attempt2(length):
listy=[]
for i in range(0,length):
if i == 0:
listy.append(1)
elif i == 1:
listy.append(1)
else:
listy.append(listy[i -1]+listy[i - 2])
return listy
print(attempt2(12))
#[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144]
Listy[-1] returns the last element of your list.
List position is initialising at 0 not 1.
When i = 2, in your else statement
listy.append(listy[i]+listy[i-1]) is equivalent to listy.append(listy[2]+listy[1])
Yet, your list after the second loop is equal to [1,1].
The max pos is 1 and 2 is out of range.
def loop_fib(n):
# first two numbers are 1
fib_1=1
fib_2=1
res=[1,1]
# n is inclusive
for i in range(3,n+1):
# new fib_2=fib_1+fib_2
# new fib_1=old fib_2
fib_1,fib_2=fib_2,fib_1+fib_2
res.append(fib_2)
return res
loop_fib(10)
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

Add a 0 after each even number in list [closed]

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 5 years ago.
Improve this question
I am trying to add a 0 after each even number, every time i run the code it infinitely prints the value of i, which is 0 every time.
I've tried this so far:
def linear_list (n):
x = []
for y in range (1, n+1):
x.append (y)
return x
n = int (input ("Enter the lenght of the list: "))
alist = linear_list (n)
for i in alist:
print (i)
if i % 2 == 0:
alist.append(0)
print (alist)
But for i >= 2my code is printing infinite zeroes:
Enter the lenght of the list: 5
0
0
0
0
...
Expected output:
[1, 2, 0, 3, 4, 0, 5, 6, 0, 7, 8, 0, 9, 10, 0]
How can achieve the correct list?
Make it work, make it right, make it fast
Here the make it work part.
You are modifying the list and iterating it at the same time.
Try:
otherlist = []
for i in alist:
print (i)
otherlist.append(i)
if i % 2 == 0:
otherlist.append(0)
print (otherlist)
You're increasing the alist length every time you append to it, and since you're looping through it you will never exit the loop - the list never ends. You don't want to change the list, but the value within it, so enumerate it:
for i, v in enumerate(alist):
print (v)
if v % 2 == 0:
alist[i] = v * 10 # assuming it's a number, use v + "0" if its a string
The iterator create by the for loop is a separate object from the list you iterate over. Your for loop is similar to a while loop like
itr = iter(a)
while True:
try:
i = next(itr)
except StopIteration:
break
if i % 2 == 0:
a.append(0)
a.append always adds a 0 to the end of the list, without affecting the current position of the iterator. Since 0 is even, once the iterator reaches the what was the end of the list when you started the loop, it sees a 0, and so another 0 gets added to the end of the list. It continues reading the next 0 and adding another 0, on and on, forever.
Technically, you can do what you want, but it's rather tricky and very easy to get wrong. (It took me about 8 tries to get this example right.) The trick is to create a separate iterator explicitly, one that you can access in the body of the loop, rather than letting the for loop generate the iterator for you. This allows you to insert a 0 after the current value in the list, then skip over the new 0 so that you won't see it on the next iteration of the loop.
Don't actually do this if you can avoid it: it is far simpler to create a new list that replaces the old list after the loop.
That said, on with the show:
a = range(10)
itr = enumerate(a) # A list of index, value pairs
for index, value in itr:
if value % 2 == 0:
i = index + 1
a[i:i] = [0] # Put a 0 after the current position
next(itr) # Skip over the 0 you just added
assert a == [0, 0, 1, 2, 0, 3, 4, 0, 5, 6, 0, 7, 8, 0, 9]
You can shorten this a bit by starting the index at 1 instead of 0, effectively pre-adding 1 to each index before you need it.
a = range(10)
itr = enumerate(a, start=1)
for i, value in itr:
if value % 2 == 0:
a[i:i] = [0]
next(itr)

Function to Create a Zigzag Array in Python

I'm trying to create an array of positive and negative integers, representing distances north and south of a location - I need to see the elements of the array in zigzag order.
This means that the largest member appears first, the smallest member appears second, and the remaining elements alternate between the larger members decreasing from the largest and the smaller members increasing from the smallest.
I.e. the array [1, 3, 6, 9, -3] becomes [9, -3, 6, 1, 3].
I'm trying to complete the function wiggleArrangeArray, which takes one argument, an integer array of n integers.
Required Input Format, Constraints, and Output Format
I'm not sure how to say
"if the item in the array is larger than the other items in the array, display it first."
"if the item is smaller than the other items in the array, display it second."
"then alternate between the next largest numbers, and the next smallest numbers"
def wiggleArrangeArray(intArr):
for i in intArr
#if i > other items in intArr
#display that i at index value 0
#if i < other items in intArr
#display that i at index value 1
#if i < i at index value 0 and > other items in intArr, display it next
#if i > i at index value 1 and < other items in intArr, display it next
#repeat last two lines for continuing values
Please help if possible. Here's a link to the solution in C++ but I need it in Python. Thanks.
Edit: The function needs to work with the following tests:
f = open(os.environ["OUTPUT_PATH"], "w")
_intArr_cnt = int(raw_input())
_intArr_i=0
_intARR = []
while _intArr_i < _intArr_cnt:
_intArr_item = int(raw_input());
_intArr.append(_intArr_item)
_intArr_i+=1
res = wiggleArrangeArray(_intArr);
for res_cur in res:
f.write( str(res_cur) + "\n" )
f.close()
The altered C++ code
Note the algorithm you provided does calculate some sort of zigzag, but it is not the zigzag you are looking for. For future reference I will leave it here.
In the C++ code you provided, they only look for a sequences that satisfies a < b > c < d > e < f, you are looking however for a sequence with the 1-max, 1-min, 2-max, 2-min,...
Your link provides you a solution which you can copy nearly verbatim in Python. You only define a swap function:
def swap(arr,i,j):
t = arr[i]
arr[i] = arr[j]
arr[j] = t
Next you can simply modify the code:
def zigZag(arr):
n = len(arr)
# Flag true indicates relation "<" is expected,
# else ">" is expected. The first expected relation
# is "<"
flag = True
i = 0
while i<= n-2:
if (flag): # "<" relation expected
# If we have a situation like A > B > C,
# we get A > B < C by swapping B and C
if arr[i] > arr[i+1]:
swap(arr,i,i+1)
else: # ">" relation expected
# If we have a situation like A < B < C,
# we get A < C > B by swapping B and C
if arr[i] < arr[i+1]:
swap(arr,i,i+1)
flag = not flag # flip flag
i += 1
Mind that this is rather un-Pythonic, so you can simply improve it like:
def swap(arr,i,j):
arr[i],arr[j] = arr[j],arr[i]
def zigZag(arr):
n = len(arr)
for i in range(len(arr)-1):
if not i&1:
if arr[i] > arr[i+1]:
swap(arr,i,i+1)
elif arr[i] < arr[i+1]:
swap(arr,i,i+1)
return arr
Here tuple assignment is used to swap elements in the list, a range is used to iterate over the indices, we can furthermore use an elif instead of an if in an else, and for I've abandoned the flag by using a modulo check.
Your zigzag function
You can simply solve the problem by sorting the list, and using two pointers that each time emit the most left, the most right and walk towards each other. In other words something like:
def zigZag(arr):
srt = sorted(arr)
left = 0
right = len(srt)-1
result = []
while left < right:
result.append(srt[right])
right -= 1
if left < right:
result.append(srt[left])
left += 1
return result
Here Python implementation example.
Sort your data in reversed order (9, 6, 3, 1, -3)
Split by two lists (9, 6) (3, 1, -3)
Iterate over both (using zip_longest) first one from start, second in reverse order (9, -3), (6, 1) (None, 3)
Unpack tuples created by zip_longest (chain(*zip...)) so you get iterable data (9, -3, 6, 1, None, 3)
Remove None value in case if the list has an odd number of elements (if x is not None)
Example:
from itertools import zip_longest, chain
def zig_zag_array(data):
data = sorted(data)
mid = len(data) // 2
return [
x for x in chain(*zip_longest(data[mid:][::-1], data[:mid])) if x is not None
]
Test:
if __name__ == "__main__":
data = [1, 3, 6, 9, -3]
expected = [9, -3, 6, 1, 3]
output = zig_zag_array(data)
assert output == expected, f"Odd length: {output=}"
data = [1, 3, 6, 9, -3, 0]
expected = [9, -3, 6, 0, 3, 1]
output = zig_zag_array(data)
assert output == expected, f"Even length: {output=}"
print("PASSED")

Traversing a Python list and making in-place changes

My task is to remove all instances of one particular element ('6' in this example) and move those to the end of the list. The requirement is to traverse a list making in-line changes (creating no supplemental lists).
Input example: [6,4,6,2,3,6,9,6,1,6,5]
Output example: [4,2,3,9,1,5,6,6,6,6,6]
So far, I have been able to do this only by making supplemental lists (breaking the task's requirements), so this working code is not allowed:
def shift_sixes(nums):
b = []
c = 0
d = []
for i in nums:
if i == 6:
b.insert(len(nums),i)
elif i != 6:
c = c +1
d.insert(c,i)
ans = d + b
return ans
I've also tried list.remove() and list.insert() but have gotten into trouble with the indexing (which moves when I insert() then move the element to the end): For example -
a = [6,4,6,2,3,6,9,6,1,6,5]
def shift_sixes(nums):
for i in nums:
if i == 6:
nums.remove(i)
nums.insert(nums[len(nums)-1], 0)
elif i != 0:
i
shift_sixes(a)
Additionally, I have tried to use the enumerate() function as follows, but run into problems on the right hand side of the b[idx] assigment line:
for idx, b in enumerate(a):
a[idx] = ???
Have read other stackoverflow entries here, here and here, but they do not tackle the movment of the element to one end.
Would appreciate any help on this list traversal / inplace switching issue. Many thanks.
EDIT
#eph - thank you. this is indeed an elegant response. I am sure it will pass my 'no new list' requirement? I surely intend to learn more about lambda and its uses
#falsetru - thank you for the reminder of the append/pop combination (which I tried to do in my original query via list.remove() and list.insert()
#tdelaney - thank you as well. somehow your response is closest to what I was attempting, but it seems not to pass the test for [0, 0, 5].
It is a bad idea to modify list while traverse. You can either make a copy to traverse, or generate a new list during traverse.
In fact, the question can be done in many ways, such as:
>>> a.sort(key = lambda i: i == 6)
>>> a
[4, 2, 3, 9, 1, 5, 6, 6, 6, 6, 6]
Iterating the list reverse way, pop the element if it's 6, then append it.
xs = [6,4,6,2,3,6,9,6,1,6,5]
for i in range(len(xs)-1, -1, -1): # 10 to 0
if xs[i] == 6:
xs.append(xs.pop(i))
Why not try something like this?
Basically, the approach is to first count the number of values.
If 0, then returns (since Python produces a ValueError if the list.index method is called for an element not in the list).
We can then set the first acceptable index for the value to be the length of the list minus the number of occurrences it exists in the list.
We can then combine list.pop/list.append to then traverse the list until all the values desired occur at the end of the list.
def shift_value(lst, value):
counts = lst.count(value) # 5
if not counts:
return lst
value_index = len(lst) - counts
index = lst.index(value)
while index != value_index:
lst.append(lst.pop(index))
index = lst.index(value)
return lst
lst = [6,4,6,2,3,6,9,6,1,6,5]
print(shift_value(lst, 6))
EDIT: This is horribly inefficient, better answer suggested above.
This requires O(n^2) time, rather than O(n) time.
The key term here is "In Line". The way you do that is move num[i] = num[i+1] for each i to the end of the list.
def shift_sixes(num):
for i, val in enumerate(num):
if val == 6:
# shift remaining items down
for j in range(i,len(num)-1):
num[j] = num[j+1]
# add 6 at the end
num[-1] = 6
return num
print(shift_sixes([1,9,4,6,2,7,8,6,2,2,6]))
print(shift_sixes([1,2,3]))
print(shift_sixes([6]))
print(shift_sixes([3]))
Use two runners. First from front to end checking for 6s, second from end to front pointing to last item that's not a 6. Keep swapping (a[i+1], a[i] = a[i], a[i+1]) until they meet.
Catch: this is not stable like in a stable sort. But I don't see that as a requirement.
Will try to write working code when in front of a python interpreter with a keyboard.
In case you need a stable sort (i.e. order of elements that are not 6 should remain the same), then the solution is:
def move_to_end(data, value):
current = 0 # Instead of iterating with for, we iterate with index
processed = 0 # How many elements we already found and moved to end of list
length = len(data) # How many elements we must process
while current + processed < length: # While there's still data to process
if data[current] == value: # If current element matches condition
data.append(data.pop(current)) # We remove it from list and append to end
processed += 1 # Our index remains the same since list shifted, but we increase number of processed elements
else: # If current element is not a match
current += 1 # We increase our index and proceed to next element
if __name__ == '__main__':
print
print 'Some testing:'
print
for test_case in (
[1, 9, 4, 6, 2, 7, 8, 6, 2, 2, 6], # Generic case
[6, 6, 6, 6], # All items are 6
[1, 7], # No items are 6
[], # No items at all
):
print 'Raw:', test_case
move_to_end(test_case, 6)
print 'Becomes:', test_case
print
Note that this solution retains the order of not only non-matching elements, but of matching elements as well. So for example, if you change the check condition from "equal to 6" to "is an even number", all elements matching the condition will be moved to the end of list while retaining their order among themselves.
Why not keep it simple?
a = [6,4,6,2,3,6,9,6,1,6,5]
def shift_sixes(nums):
for i in range(0,len(nums)):
if nums[i] == 6:
nums.append(nums.pop(i))
>>> shift_sixes(a)
>>> a
[3, 9, 1, 5, 2, 4, 6, 6, 6, 6]

Categories

Resources