Print set() item fill with python generator - python

I have a generator:
foundUnique = set()
def unique_items(myList, index, clearFlag):
for item in myList:
if clearFlag is True:
foundUnique.clear()
clearFlag = False
if item[index] not in foundUnique:
yield item
foundUnique.add(item[index])
And I am using this `unique_items to get a unique list:
senderDupSend = unique_items(ip, 4, True)
Now I want my set to be reachable (I can print its element or do some changes on specific element .....) but when I write:
for item in foundUnique:
print item
It prints nothing!
But if I write:
for item in senderDupSend:
print item
for item in foundUnique:
print item
It prints all foundUnique items.
Please tell what did I do wrong? How can I solve this problem?

The problem is that unique_items is a generator so that
senderDupSend = unique_items(ip, 4, True)
is a generator that needs to be iterated over. When you run
for item in foundUnique:
print item
the generator has not actually run yet so foundUnique is still empty.
When you later go on to do
for item in senderDupSend: # This is what actually fills the list.
print item
for item in foundUnique:
print item
It should print out the set twice: once while it is being constructed and once after it is constructed.
It seems like what you are trying to do is construct a set that has the same index taken from every element of some sequence. You can do it like this very easily:
found_unique = set(item[index] for item in sequence)
In the concrete case that you show, it would be:
found_unique = set(item[4] for item in ip)
If you later wanted to extend the set to contain other items, you could do
found_unique.union(item[4] for item in other_ip_list)

Related

Which item in list - Python

I am making a console game using python and I am checking if an item is in a list using:
if variable in list:
I want to check which variable in that list it was like list[0] for example. Any help would be appreciated :)
You can do it using the list class attribute index as following:
list.index(variable)
Index gives you an integer that matches the location of the first appearance of the value you are looking for, and it will throw an error if the value is not found.
If you are already checking if the value is in the list, then within the if statement you can get the index by:
if variable in list:
variable_at = list.index(variable)
Example:
foo = ['this','is','not','This','it','is','that','This']
if 'This' in foo:
print(foo.index('This'))
Outputs:
3
Take a look at the answer below, which has more complete information.
Finding the index of an item in a list
We may be inspired from other languages such as Javascript and create a function which returns index if item exists or -1 otherwise.
list_ = [5, 6, 7, 8]
def check_element(alist: list, item: any):
if item in alist:
return alist.index(item)
else:
return -1
and the usage is
check1 = check_element(list_, 5)
check2 = check_element(list_, 9)
and this one is for one line lovers
check_element_one_liner = lambda alist, item: alist.index(item) if item in alist else -1
alternative_check1 = check_element_one_liner(list_, 5)
alternative_check2 = check_element_one_liner(list_, 9)
and a bit shorter version :)
check_shorter = lambda a, i: a.index(i) if i in a else -1
Using a librairy you could use numpy's np.where(list == variable).
In vanilla Python, I can think of something like:
idx = [idx for idx, item in enumerate(list) if item == variable][0]
But this solution is not fool proof, for instance, if theres no matching results, it will crash. You could complete this using an if right before:
if variable in list:
idx = [idx for idx, item in enumerate(list) if item == variable][0]
else:
idx = None
I understand that you want to get a sublist containing only the elements of the original list that match a certain condition (in your example case, you want to extract all the elements that are equal to the first element of the list).
You can do that by using the built-in filter function which allows you to produce a new list containing only the elements that match a specific condition.
Here's an example:
a = [1,1,1,3,4]
variable = a[0]
b = list(filter(lambda x : x == variable, a)) # [1,1,1]
This answer assumes that you only search for one (the first) matching element in the list.
Using the index method of a list should be the way to go. You just have to wrap it in a try-except statement. Here is an alternative version using next.
def get_index(data, search):
return next((index for index, value in enumerate(data) if value == search), None)
my_list = list('ABCDEFGH')
print(get_index(my_list, 'C'))
print(get_index(my_list, 'X'))
The output is
2
None
assuming that you want to check that it exists and get its index, the most efficient way is to use list.index , it returns the first item index found, otherwise it raises an error so it can be used as follows:
items = [1,2,3,4,5]
item_index = None
try:
item_index = items.index(3) # look for 3 in the list
except ValueError:
# do item not found logic
print("item not found") # example
else:
# do item found logic knowing item_index
print(items[item_index]) # example, prints 3
also please avoid naming variables list as it overrides the built-in function list.
If you simply want to check if the number is in the list and print it or print it's index, you could simply try this:
ls = [1,2,3]
num = 2
if num in ls:
# to print the num
print(num)
# to print the index of num
print(ls.index(num))
else:
print('Number not in the list')
animals = ['cat', 'dog', 'rabbit', 'horse']
index = animals.index('dog')
print(index)

How to check if any item in list starts with string and if so how to get item index?

elif any(item.startswith('qwerty') for item in myList):
itemIndex = myList.index(item)
"item" is not defined
I want to assign item's index to a variable.
From Python 3.8 onwards, you can use an assignment expression inside any to capture the value in the expression.
Something like this:
elif any((found:=item).startswith('qwerty') for item in myList):
itemIndex = myList.index(found)
Alternatively, you could replace any with next, which will give you the found value:
found = next((item for item in myList if item.startswith('qwerty')), None)
if found is not None:
itemIndex = myList.index(found)
Or you could use enumerate and get the index without needing to look it up separately:
index = next((i for (i,item) in enumerate(myList) if item.startswith('qwerty')), None)
You may also try something like this
elif any([item.startswith("qwerty") for item in myList]):
itemindex = [myList.index(item) for item in myList if item.startswith("qwerty")]

Returns list index out of range when i iterate through my list

inp = [1,2,3,5,6]
def o(k):
x =[]
for item in k:
if item != k[item-1] and item != item+1:
x.append(item)
When I try to run the code with my input it just says
"list out of range"
Hi based on your code I understand that you are working on the assumption that item is the index of the array. But that is not the way the for item in k: loop works in python. On each iteration item will be the next 'element' of the array rather than the next 'index'. Also item != item + 1 does not make any sense since it will be always true. I think you meant to write k[item] != k[item + 1].

How to do something only to the first item within a loop in python? [duplicate]

This question already has answers here:
"For" loop first iteration
(13 answers)
Closed last year.
I want to do something different to the the first item in a list. What is the most pythonic way of doing so?
for item in list:
# only if its the first item, do something
# otherwise do something else
A few choices, in descending order of Pythonicity:
for index, item in enumerate(lst): # note: don't use list
if not index: # or if index == 0:
# first item
else:
# other items
Or:
first = True
for item in lst:
if first:
first = False
# first item
else:
# other items
Or:
for index in range(len(lst)):
item = lst[i]
if not index:
# first item
else:
# other items
You can create an iterator over the list using iter(), then call next() on it to get the first value, then loop on the remainder. I find this a quite elegent way to handle files where the first line is the header and the rest is data, i.e.
list_iterator = iter(lst)
# consume the first item
first_item = next(list_iterator)
# now loop on the tail
for item in list_iterator:
print(item)
do_something_with_first_item(lst[0])
for item in lst[1:]:
do_something_else(item)
Or:
is_first_item = True
for item in lst:
if is_first_item:
do_something_with_first_item(item)
is_first_item = False
else:
do_something_else(item)
Do not use list as a variable name, because this shadows the built-in function list().
The enumerate-based solution in jonrsharpe's answer is superior to this. You should probably use that instead.
Use a flag that you change after processing the first item. For example:
first = True
for item in my_list:
if first:
# Processing unique to the first item
first = False
else:
# Processing unique to other items
# Shared processing
You could also just process the first item:
first = my_list.pop(0)
# Process first
for item in my_list:
# Process item
# Add the first item back to the list at the beginning
my_list.insert(0, first)
jonrsharpe's first version using enumerate is clean and simple, and works with all iterables:
for index, item in enumerate(lst):
if not index:
do_something_with_first_item(item)
else:
do_something_else(item)
senshin's first solution using lst[0] and lst[1:] is even simpler, but only works with sequences:
do_something_with_first_item(lst[0])
for item in lst[1:]:
do_something_else(item)
You can get the best of both worlds by using iterators directly:
it = iter(lst)
do_something_with_first_item(next(it))
for item in it:
do_something_else(item)
But, despite being the best of both worlds, it's actually not quite as simple as either. This is only clearly worth doing if you know you have an iterator (so you can skip the first line), or you need one anyway to do itertools and genexpr and similar stuff to (so you were already going to write the first line). Whether it's worth doing in other cases is more of a style issue.

better for-loop syntax for detecting empty sequences?

Is there a better way to write the following:
row_counter = 0
for item in iterable_sequence:
# do stuff with the item
counter += 1
if not row_counter:
# handle the empty-sequence-case
Please keep in mind that I can't use len(iterable_sequence) because 1) not all sequences have known lengths; 2) in some cases calling len() may trigger loading of the sequence's items into memory (as the case would be with sql query results).
The reason I ask is that I'm simply curious if there is a way to make above more concise and idiomatic. What I'm looking for is along the lines of:
for item in sequence:
#process item
*else*:
#handle the empty sequence case
(assuming "else" here worked only on empty sequences, which I know it doesn't)
for item in iterable:
break
else:
# handle the empty-sequence-case here
Or
item = next(iterator, sentinel)
if item is sentinel:
# handle the empty-sequence-case here
In each case one item is consumed if it is present.
An example of empty_adapter()'s implementation mentioned in the comments:
def empty_adaptor(iterable, sentinel=object()):
it = iter(iterable)
item = next(it, sentinel)
if item is sentinel:
return None # empty
else:
def gen():
yield item
for i in it:
yield i
return gen()
You could use it as follows:
it = empty_adaptor(some_iter)
if it is not None:
for i in it:
# handle items
else:
# handle empty case
Introducing special case for an empty sequence for a general case seems wrong. There should be a better solution for a domain specific problem.
It may be a job for itertools.tee
You "trigger" the sequence on the verification, but you are left with an untouched copy of the sequence afterwards:
from itertools import tee
check, sequence = tee(sequence, 2)
try:
check.next():
except StopIteration:
#empty sequence
for item in sequence:
#do stuff
(it's worth nting that tee does the "right" thing here: it will load just the first element of the sequence in the moment check.next() is executed - and this first elment will remain available in the sequence. The remaining items will only be retrieved as part of the for loop
Or just keeping it simple:
If you can't use len, you can't check if the sequence has a bool value of True, for the same reasons.
Therefore, your way seens simple enough -
another way would be to delete the name "item" before the "for" statement and
check if it exists after the loop:
del item
for item in sequence:
# do stuff
try:
item
except NameError:
# sequence is empty.
But your code should be used as its more clear than this.
The second example from J.F. Sebastian seems to be the ticket with a while loop.
NoItem = object()
myiter = (x for x in range(10))
item = next(myiter, NoItem)
if item is NoItem:
...
else:
while item is not NoItem:
print item
item = next(myiter, NoItem)
Not the most concise but objectively the clearest... Mud, no?
This shouldn't trigger len():
def handle_items(items):
index = -1
for index, item in enumerate(items):
print 'processing item #%d: %r' % (index, item)
# at this point, index will be the offset of the last item,
# i.e. length of items minus one
if index == -1:
print 'there were no items to process'
print 'done'
print
# test with an empty generator and two generators of different length:
handle_items(x for x in ())
handle_items(x for x in (1,))
handle_items(x for x in (1, 2, 3))
if not iterable_sequence.__length_hint__():
empty()
else:
for item in iterable_sequence:
dostuff()

Categories

Resources