Trying to make a function to find a specified target [closed] - python

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 7 months ago.
Improve this question
So I am trying to make a searching function. But that doesn't work right everytime. Gives the right output sometimes tough. Here is what i did:
import random
def normal_search(l, target):
# printing the list
l1 = l
x = ' '.join([str(l)])
print(f'The list is {x}')
choose = random.choice(l)
if choose == target:
index = l.index(choose)
index += 1
print(f"I found it! It's {index}. element.")
while choose != target:
l.remove(choose)
choose = random.choice(l)
print(choose)
index = l1.index(choose)
index += 1
print(f"normal_search I found it! It's {index}. element.")
# creating a shuffled list of 0 to 10
a = []
n = 0
while len(a) < 10:
n += 1
a.append(n)
random.shuffle(a)
normal_search(a, 5)
I am trying to get the target as output. What is making the output wrong?

I think the error is due to the fact that every time it does not find the target element the list decreases by 1 and if the removed element is before the target element it will change index.
I think the only solution is to stop removing the wrong elements, this would guarantee the correct functioning of the program but would increase its execution times.

import random
def normal_search(l, target):
# printing the list
x = ' '.join([str(l)])
print(f'The list is {x}')
while True:
choose = random.choice(l)
if choose == target:
index = l.index(choose)
index += 1
print(f"normal_search I found it! It's {index}. element.")
break
# creating a shuffled list of 0 to 10
a = list(range(10))
random.shuffle(a)
normal_search(a, 5)
As #FraRomee said, you are removing one element every step, suppose at first you have a list like: [0, 6, 4, 2, 3, 5, 1, 8, 9, 7], and index(5) is 6 and you randomly choose an element: 3 and it is not equal to 5 and you remove it, then you have [0, 6, 4, 2, 5, 1, 8, 9, 7] and length of list is 9 and index(5) is 5
and so on you choose 6 and remove it and you have [0, 4, 2, 5, 1, 8, 9, 7].
so if this time you select 5 correctly, index is 4 and it is correct for new list but is wrong for initial list and you cant use it for your own.
my code points:
you can create a list from a to b using list(range(a,b+1)) and you don't need while loop.
you can choose all elements from first in while body using break statement. if condition is False, so break loop, if not, go on and choose a new element.

Related

How remove elements in array with out messing with the counter or list length

Codewars: Given a list lst and a number N, create a new list that contains each number of lst at most N times without reordering. For example if N = 2, and the input is [1,2,3,1,2,1,2,3], you take [1,2,3,1,2], drop the next [1,2] since this would lead to 1 and 2 being in the result 3 times, and then take 3, which leads to [1,2,3,1,2,3].
delete_nth ([1,1,1,1],2) # return [1,1]
delete_nth ([20,37,20,21],1) # return [20,37,21]
I'll loop through the array to find the elements that have more than "x" amount. But The problem for me is that when I want to remove that element it changes the length of the array there for throwing off my loop counter. And then when I try another way by creating another list and then again looping through the original list and seeing if the element has more than "x" amount then I'll copy that element into the new array leaving the old array alone and it keeping its index and the loop is fine but now I do not know how to stop copying the element once it hits its desired amount. Please help me. I have been on this answer for a week now.
Maybe you could try this snippet to see that helps?
Have not done too many edge cases - so please raise questions, if run into some edges.
def delete_nth(lst, N):
seen = {}
res = []
for x in lst:
if x not in seen :
seen[x] = 0
else:
seen[x] += 1
if seen[x] <N:
res.append(x)
return res
print(delete_nth([1, 1, 1, 1], 2)) # [1, 1]
print(delete_nth([20, 37, 20, 22], 1)) # [20, 37, 22]

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)

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]

Randint number into a Dict [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
Is it possible to add a random number create with random.randint to a Dict ? Or is it better to add it to a List. I ask because I wan to get random.randit(0,100) and check it the List or Dict have already the number that is now generated and print out the possition on which the second same number is
So I already tried it with append to a dict but that doesn' work!
EDIT
import random
randomdict = {}
numbposition = {}
def randomnumber(numb):
for i in random.randint(0,numb+1):
randomdict.append(i)
if i in randomdict:
numbposition.index(i)
print (numbposition)
print (randomdict)
while True:
numb = int(input('Give me number: '))
print(randomnumber(numb))
break
It is certainly possible to add the value returned by random.randint to a dictionary or list; it's just an integer, and can be treated like any other. However, you cannot append to a dictionary; that syntax is for adding to the end of a list, to add a new object to a dictionary use d[key] = value. Also, dictionaries don't have an index in the same way that e.g. lists and tuples do; just a key, and no guaranteed order.
Here is an example that is close to what you're describing:
import random
l = []
for _ in range(10):
n = random.randint(0, 10)
print(n)
if n not in l:
print("New item.")
l.append(n)
else:
print("Item found at index {0}.".format(l.index(n)))
print(l)
The output from this is:
2
New item.
2
Item found at index 0.
2
Item found at index 0.
1
New item.
3
New item.
10
New item.
6
New item.
4
New item.
4
Item found at index 5.
10
Item found at index 3.
[2, 1, 3, 10, 6, 4]
Edit
To add all numbers and get the largest preexisting index, you need a slight tweak:
if n not in l:
print("New item.")
else:
index = max(i for i, v in enumerate(l) if v == n)
print("Item found at index {0}.".format(index))
l.append(n)
Note that append is moved to the end (so the new n isn't in the list when we look for the largest prior index) and we can no longer use list.index (which finds the first index) - a more complex calculation is required.
This gives:
0
New item.
4
New item.
10
New item.
10
Item found at index 2.
3
New item.
4
Item found at index 1.
1
New item.
8
New item.
8
Item found at index 7.
1
Item found at index 6.
[0, 4, 10, 10, 3, 4, 1, 8, 8, 1]

Categories

Resources