A given list looks like this
list = [1,2,3,4,5,6,4,0]
I would like to duplicate every occurrence of 4
so the output looks like this:
[1,2,3,4,4,5,6,4,4,0]
I tried to do it like this:
def dup(list):
counter = 0
for value in list:
if value == 4:
print(counter,value)
list.insert(counter,4)
counter += 1
print(dup([1,2,3,4,5,6,4,0]))
I stumbled on a problem when I inserted int into a list index shifts with it. And I am stuck in an infinite loop of inserting 4
Also I would like the change to be done in place.
l = []
for n in nums:
l.append(num)
if n == 4:
l.append(4)
or inplace (you need to increment the counter twice)
i = 0
while i < len(nums):
if nums[i] == 4:
nums.insert(i, 4)
i += 1
i += 1
Related
This question already has answers here:
How to remove items from a list while iterating?
(25 answers)
Strange result when removing item from a list while iterating over it
(8 answers)
Closed 5 months ago.
Imagine I have a list L that has the following items:
L = [1,1,2,3]
Let's say that I want to remove each item but also count the amount of "ones", "twos" and "threes" that are on the list. So we define the following variables
ones = 0
twos = 0
threes = 0
One way I tried to solve this problem was by using a for loop and a while loop in the following way:
for item in L:
while item in L:
if item == 1:
ones += 1
L.remove(item)
elif item == 2:
twos += 1
L.remove(item)
elif item == 3:
threes += 1
L.remove(item)
But for whatever reason, the list L remains as
L = [2]
and the variables
ones = 2
twos = 0
threes = 1
Can someone explain why is it not removing and counting the 2 and how to fix it?
Thank you in advance.
P.S. I am aware of a way of counting items on a list (count method for example) but I would still like to know why this is happening
When you start iterating over the list of numbers, you shouldn't be altering the list itself, an idea may be to copy the values to a second list and use it as support for the loop
a = [1,1,2,3]
b = a.copy()
count = {}
for i in b:
print(i)
if i in count:
count[i] += 1
else:
count[i] = 1
a.remove(i)
print(count)
The for loop considers the value at each index in L.
The first iteration of the for considers value at index 0.
The second iteration of the for considers value at index 1.
Since you modify the list in-situ, by the time index 1 is considered, the value there is 3.
The value 2 isn't considered because that moves to index 0, which has already been considered at that point in time.
To help illustrate this, I've used the enumerate function to expose both index and value in your for loop:
#!/usr/bin/env python
L = [1,1,2,3]
ones = 0
twos = 0
threes = 0
for index, item in enumerate(L):
print(f"Consider value at index {index} in {L} (value: {item})")
while item in L:
if item == 1:
ones += 1
L.remove(item)
elif item == 2:
twos += 1
L.remove(item)
elif item == 3:
threes += 1
L.remove(item)
# Consider value at index 0 in [1, 1, 2, 3] (value: 1)
# Consider value at index 1 in [2, 3] (value: 3)
You can fix this by iterating over a copy of the list in your for.
One way of making a copy of it is to append an empty list, making a new list that's the same.
To do this, change your for to be:
for item in L+[]:
Alternatively, you can create a more concise solution by using list.count in a dict comprehension:
#!/usr/bin/env python
L = [1,1,2,3]
counts = { i:L.count(i) for i in set(L) }
print(counts)
Apologies if the title of the question is phrased badly. I am currently trying to make a function that takes in a list of integers from 1 to n, where n is the length of the list. The function should return the first value that is repeated in the list. Duplicates are NOT always next to one another. If one or more integers is less than 1 or if it is not a list, the function should return -1. If there are no duplicates, return 0.
This is my current code:
def find_duplicates(ls):
if type(ls) != list:
return -1
non_dupe = []
i = 0
while i < len(ls):
if ls[i] < 1:
return -1
break
if ls.count(i) > 1:
return i
break
else:
non_dupe.append(i)
i += 1
if len(non_dupe) == len(ls):
return 0
While this code works for a majority of test cases, it doesn't seem to pass
print(find_duplicates([1, 2, 2, 0]))
as it returns 2 instead of the expected -1. I am relatively new to Python and I can't seem to be able to fix this error. I've tried searching for ways to counter this problem but I am not allowed to use for loops to check through a list. Any help is greatly appreciated.
EDIT: I am not allowed to use any of the following but anything else is accepted.
for loops
min() / max()
enumerate() / zip ()
sort()
negative indexing e.g ls[-1]
list slicing
Your code returns a duplicate prematurely; traversing the list, the function first finds 2 as a duplicate, return it, and halts the function immediately. But it has not seen the 0 at the end.
So, you need to let the function see the list all the way towards the end, looking for a negative number. If a negative number is found along the way, you can halt the function. If it does not see a negative number until the end, then let it return the duplicate value:
def find_duplicates(ls):
if not isinstance(ls, list): # check whether ls is a list
return -1
dup = 0
seen = [] # list of numbers seen so far
i = 0 # index
while i < len(ls):
if ls[i] < 1: # if a negative number is found, return -1
return -1
if ls[i] in seen and dup == 0:
dup = ls[i]
seen.append(ls[i])
i += 1
return dup
print(find_duplicates([1, 2, 2, 0])) # -1
print(find_duplicates([1, 1, 2, 2, 3])) # 1
Problem is beacause you are breaking while loop when find a duplicated. In that case, function is finding first the duplicated.
Try this:
def find_duplicates(ls):
if type(ls) is not list:
return -1
duplicated = 0
i = 0
while i < len(ls):
if ls[i] < 1:
return -1
if ls.count(ls[i]) > 1 and duplicated == 0
duplicated = ls[i]
i += 1
return duplicated
Your test case returns 2 because 2 stay at lower indexes comparing to 0.
I would suggest to sort the list before moving on:
def find_duplicates(ls):
if type(ls) != list:
return -1
sorted_list = ls.sorted() #Assign sorted `ls` to another variable, while keeping the order of `ls` intact
non_dupe = []
i = 0
while i < len(ls):
if ls[i] < 1:
return -1
break
if ls.count(i) > 1:
return i
break
else:
non_dupe.append(i)
i += 1
if len(non_dupe) == len(ls):
return 0
Another method I would recommend is using set - a built-in data type of Python. Maybe you should consider trying this approach later on when all test cases are passed. Have a look at this Tutorial for set usage: https://www.w3schools.com/python/python_sets.asp.
You were very close. Try this:
def find_duplicates(ls):
if type(ls) != list:
return -1
non_dupe = []
i = 0
while i < len(ls):
if ls[i] < 1:
return -1
elif ls[i] in non_dupe:
return ls[i]
else:
non_dupe.append(i)
i += 1
return 0
my_list = [1,2,2,0]
result = list(set(filter(lambda x: my_list.count(x) > 1 , my_list)))
# Result => [2]
I hope this solves your problem
I am trying to count the instances of "1" appearing in a list. When I used index to access the elements in the list and implement a counter, the total number of count is always 1.
However, when I used the normal "for" iterations, the count actually works. Could anyone enlighten me?
Here's a snippet of what DOES NOT work:
for entry in range(len(nums)):
count = counts = 0
if nums[entry] == 1:
count = count + 1
print(count)
Here's a snippet of what works:
for num in nums:
if num == 1:
counts = counts + 1
This is because you define the counter inside the for-loop and thus it gets reset to 0 in each iteration.
Just make sure to define the counter outside of the for loop
count = 0
for entry in range(len(nums)):
if nums[entry] == 1:
count = count + 1
print(count)
EDIT: The terminology I was looking for was is called Cycle Detection. Thanks to #dhke for referring that in the comments.
I'm trying to figure out a better way to process a list of indexes and what it's length is if a list has a loop in its reference. I have a function that works but it passes the next index value and counter. I've been trying to figure out a way to do it by just passing the list into the function. It always starts as index 0.
Given a list, each node in the list references the index of some other node. I'm trying to get the length of the linked list not the number of nodes in the list.
# This list would have a length of 4, index 0->1->3->6->0
four_links_list = [1,3,4,6,0,4,0]
two_links_list = [3,2,1,0]
def my_ideal_func(list):
# Some better way to iterate over the list and count
def my_func(list, index, counter):
# We're just starting out
if index == 0 and counter == 0:
counter += 1
return my_func(list, list[index], counter)
# Keep going through the list as long as we're not looping back around
elif index != 0:
counter += 1
return my_func(list, list[index], counter)
# Stop once we hit a node with an index reference of 0
else:
return counter
If you don't want extra data structures:
def tortoise_and_hare(l):
tort = 0
hare = 0
count = 0
while tort != hare or count == 0:
count += 1
if l[tort] == 0:
return count
tort = l[tort]
hare = l[hare]
hare = l[hare]
return -1
>>> tortoise_and_hare([1,3,4,6,0,4,0])
4
>>> tortoise_and_hare([3,2,1,0])
2
>>> tortoise_and_hare([1,2,3,1,2,1,2,1])
-1
You can use a set to keep track of all nodes you've visited (sets have very fast membership tests). And there is absolutely no need for recursion here, a loop will do nicely:
def my_ideal_func(list):
visited_nodes= set()
index= 0
length= 0
while True:
node= list[index]
if node in visited_nodes:
return length
visited_nodes.add(node)
length+= 1
index= list[index]
There's no need for recursion:
def link_len(l):
cnt, idx = 0, 0
while not cnt or idx:
cnt = cnt + 1
idx = l[idx]
return cnt
This assumes the list loops back to 0.
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.