Insert Sort Index Error? - python-3.x

I'm attempting to create an insert Sort which takes the smallest number from a list and appends it to another list.
The problem is, everything I attempt to pop() the number out of the list, I get an index error.
Here's my code:
alist = [2,9,8,6,1]
blist =[]
def insertsort(list, slist) :
for item in list:
smallest = list[0]
if item < smallest:
smallest = list[item]
list.pop(smallest)
slist.append(smallest)
insertsort(alist, blist)
print(blist)
And the error is:
IndexError: pop index out of range
Thanks in advance for any help.

When a function call fails, reads the docs, or use, in this case, >>> help(list.pop). Much faster that waiting hours for someone to answer a trivial question.
The argument to pop is an index of a value in the list, not a value itself. Your code has several other problems once this is fixed.
alist = [2,9,8,6,1]
blist =[]
def insertsort(inlist, outlist):
while inlist:
it = iter(inlist)
sdex = 0
small = next(it)
for dex, item in enumerate(it, 1):
if item < small:
sdex = dex
small = item
inlist.pop(sdex)
outlist.append(small)
insertsort(alist, blist)
print(blist)
prints [1, 2, 6, 8, 9]
The following version of the function uses the builtin min function and gives the same output.
def insertsort(inlist, outlist):
while inlist:
small = min(inlist)
inlist.pop(inlist.index(small))
outlist.append(small)

Related

cant break out of Python While loop

I'm quite new to Python so sorry in advance, I'm trying to break out of a While loop if a random number is not within a List of numbers.
Despite testing the output of the functions and confirming that an integer is in the List and it is in fact an integer and other methods return both True and False the While Statement ignores the value. See demo code.
import random,time
list=[i for i in range(10)]
print(list)
print(list[6]*10) # this returns an integer
if list[6]==12/2:
print('this evaluates as a int')
this=99 # sentry to run the while loop **** but cant index by
if 10/2 in list:
print('this also evaluates as an integer')
print(type(list))
print(type(this))
while this not in list:
this = random.randrange(9)
print(this,this in list)
time.sleep(.200)
list[this] = '*'
>>>
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
60
this evaluates as a int
this also evaluates as an integer
<class 'list'>
<class 'int'>
6 True
3 True
4 True
5 True
5 False
Its obvious there's a flaw in the While function where it is unable see True or False correctly, thank you to those who proposed suggestions but i come up with my own.
I created a sentry boolean to pass the value to the While function
sentry=True
while sentry:
this = random.randrange(9)
print(this,this in list)
if this not in list:
sentry=False
time.sleep(.200)
list[this] = '*'
The while loop condition should evaluate to False when you want to break out of the loop. In your case, since you want to exit when this is not in list, then set your condition to this in list.
Here is your code with the fixed condition, keep in mind that since the list is directly modified from inside the loop, the loop will terminate after one iteration.
import random, time
list=[i for i in range(10)]
print(list)
this = random.randrange(9)
while this in list:
this = random.randrange(9)
print(this, this in list)
time.sleep(.200)
list[this] = '*'
print(list)
If you did not want the loop to terminate after one iteration, you may want to consider relocating the expression list[this] = '*'. (Though this solution may also end after one iteration based on probability)
import random, time
list=[i for i in range(10)]
print(list)
this = random.randrange(9)
while this in list:
list[this] = '*' # moved here
print(list)
this = random.randrange(9)
print(this, this in list)
time.sleep(.200)
EDIT based on comment
Since the goal is to replace integers with *'s until no integers remain in the original list, here are some modifications.
The while loop exits when the number of elements replaced is equal to the number of items in the original array. The indices that have not been replaced yet are stored in the array called available.
import random, time
lst = [i for i in range(10)]
print(lst)
num_replaced = 0
# available = list.copy()
available = list(range(len(lst)))
while num_replaced < len(lst):
this = random.choice(available)
available.remove(this) # the index just chosen is no longer available
lst[this] = '*'
num_replaced += 1

How to subtract adjacent items in list with unknown length (python)?

Provided with a list of lists. Here's an example myList =[[70,83,90],[19,25,30]], return a list of lists which contains the difference between the elements. An example of the result would be[[13,7],[6,5]]. The absolute value of (70-83), (83-90), (19-25), and (25-30) is what is returned. I'm not sure how to iterate through the list to subtract adjacent elements without already knowing the length of the list. So far I have just separated the list of lists into two separate lists.
list_one = myList[0]
list_two = myList[1]
Please let me know what you would recommend, thank you!
A custom generator can return two adjacent items at a time from a sequence without knowing the length:
def two(sequence):
i = iter(sequence)
a = next(i)
for b in i:
yield a,b
a = b
original = [[70,83,90],[19,25,30]]
result = [[abs(a-b) for a,b in two(sequence)]
for sequence in original]
print(result)
[[13, 7], [6, 5]]
Well, for each list, you can simply get its number of elements like this:
res = []
for my_list in list_of_lists:
res.append([])
for i in range(len(my_list) - 1):
# Do some stuff
You can then add the results you want to res[-1].

The best way of iterating through an array whose length changes in Python

I am implementing an algorithm which might affect the size of some array, and I need to iterate through the entire array. Basically a 'for x in arrayname' would not work because it does not update if the contents of arrayname are changed in the loop. I came up with an ugly solution which is shown in the following example:
test = np.array([1,2,3])
N = len(test)
ii=0
while ii < N:
N = len(test)
print(test[ii])
if test[ii] ==2:
test = np.append(test,4)
ii+=1
I am wondering whether a cleaner solution exists.
Thanks in advance!
Assuming all the elements are going to be added at the end and no elements are being deleted you could store the new elements in a separate list:
master_list = [1,2,3]
curr_elems = master_list
while len(curr_elems) > 0: # keep looping over new elements added
new_elems = []
for item in curr_elems: # loop over the current list of elements, initially the list but then all the added elements on second run etc
if should_add_element(item):
new_elems.append(generate_new_element(item))
master_list.extend(new_elems) # add all the new elements to our master list
curr_elems = new_elems # and prep to iterate over the new elements for next iteration of the while loop
The while loop seems the best solution. As the condition is re-evaluated at each iteration, you don’t need to reset the length of the list in the loop, you can do it inside the condition:
import random
l = [1, 2, 3, 4, 5]
i = 0
while i < len(l):
if random.choice([True, False]):
del l[i]
else:
i += 1
print(f'{l=}')
This example gives a blueprint for a more complex algorithm. Of course, in this simple case, it could be coded more simply with a filter, or like this:
l = [1, 2, 3, 4, 5]
[x for x in l if random.choice([True, False])]
You might want to check this related post for more creative solutions: How to remove items from a list while iterating?

using for loop to count list elements in a string

Im beginner in python, learning it for biology purposes.
Ok, lets suppose I want to write a function that will iterate over a list to count how many of its elements in the string using for loop
def counting(string,lista):
for element in lista:
element_count=string.count(element)
return element_count
so when using the above function to find how many A and C in my string
print(counting('AABCDEF',['A','C']))
It seems the function only return the count of C in the string which is 1, what I want to get both elements count. It seems adding a print line inside the loop body will solve the problem,
def counting(string,lista):
for element in lista:
element_count=string.count(element)
print(element_count)
return element_count
is there a way to get the same output without using the print statement?
Thanks in advance
Return the result as a list.
def counting(string,lista):
temp = []
for element in lista:
temp.append(string.count(element))
return temp
print(counting('AABCDEF',['A','C']))
The result is
[2, 1]
To print some verbose,
def counting(string, lista):
temp = []
for element in lista:
temp.append('{} count is {}'.format(element, string.count(element)))
return ', '.join(temp)
print(counting('AABCDEF', ['A','C']))
Then
A count is 2, C count is 1

What is the empty dictionary used for in the code?

I'm doing practice problems in python on Leetcode (still learning). This is the problem:
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
my code is
class Solution:
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
dict = {}
for counter, i in enumerate(nums):
a = target- i
if a in dict:
return (dict[a], counter)
dict[i] = counter
It runs fine and passes all the tests however I found a common reason this works is for the dict = {}
What is the reason for this dictionary and how does this code recognize cases for (3,3) target = 6 where there are duplicates and index matters. A basic run down of why the code works would be great!
The dictionary stores as keys the numbers in the list with their index as a value.
For example:
[2, 7, 11, 15] -> {'2':0, '7':1, '11':2, '15':3}
There is never a duplicate inserted, if the same number appears twice, the index will be replaced with the new index where it appears.
In the case of duplicate, it is important to test all value on the first list, and to store index on a separated dict in order to be sur that you will never test in dictionnary the actually tested value.
By using a dictionnary in order to find the index of the right number, you can't store duplicate.
Since in dictionnary you can't have 2 values with the same key, if duplicate, you just change the old index with the new one.
For example, if dict == {'3': 0, '2':1} and the tested value is 2, the dict == {'3': 0, '2':2}.
And if the target is reach by duplicate number (2+2 for target 4 for example), nothing is stored cause of the return in the if a in dict: return (dict[a], counter)

Resources