Including first and last elements in list comprehension - python

I would like to keep the first and last elements of a list, and exclude others that meet defined criteria without using a loop. The first and last elements may or may not have the criteria of elements being removed.
As a very basic example,
aList = ['a','b','a','b','a']
[x for x in aList if x !='a']
returns ['b', 'b']
I need ['a','b','b','a']
I can split off the first and last values and then re-concatenate them together, but this doesn't seem very Pythonic.

You can use slice assignment:
>>> aList = ['a','b','a','b','a']
>>> aList[1:-1]=[x for x in aList[1:-1] if x !='a']
>>> aList
['a', 'b', 'b', 'a']

Yup, it looks like dawg’s and jez’s suggested answers are the right ones, here. Leaving the below for posterity.
Hmmm, your sample input and output don’t match what I think your question is, and it is absolutely pythonic to use slicing:
a_list = ['a','b','a','b','a']
# a_list = a_list[1:-1] # take everything but the first and last elements
a_list = a_list[:2] + a_list[-2:] # this gets you the [ 'a', 'b', 'b', 'a' ]

Here's a list comprehension that explicitly makes the first and last elements immune from removal, regardless of their value:
>>> aList = ['a', 'b', 'a', 'b', 'a']
>>> [ letter for index, letter in enumerate(aList) if letter != 'a' or index in [0, len(x)-1] ]
['a', 'b', 'b', 'a']

Try this:
>>> list_ = ['a', 'b', 'a', 'b', 'a']
>>> [value for index, value in enumerate(list_) if index in {0, len(list_)-1} or value == 'b']
['a', 'b', 'b', 'a']
Although, the list comprehension is becoming unwieldy. Consider writing a generator like so:
>>> def keep_bookends_and_bs(list_):
... for index, value in enumerate(list_):
... if index in {0, len(list_)-1}:
... yield value
... elif value == 'b':
... yield value
...
>>> list(keep_bookends_and_bs(list_))
['a', 'b', 'b', 'a']

Related

How to get only lowercase strings from a list using list comprehension

The question asked:
Use list comprehensions to generate a list with only the lowercase letters in my_list. Print the result list.
['a', 'A', 'b', 'B', 'c', 'C', 'd', 'D']
My code:
my_list = ['a', 'A', 'b', 'B', 'c', 'C', 'd', 'D']
hi = ([ char for char in range(len(my_list)) if char%2 == 0])
print(hi)
I tried it out, but got integers as answers and not the strings I wanted.
Note: several answers here assume that what you want is to select the values in the list that are lowercase. This answer assumes that that was an example and that the thing you're trying to do is to select the values in the list that occur at every other list index. (This seems to me to be the correct interpretation, because that's what the implementation in the question appears to be trying to do.) I'm not sure who misunderstood the question here, but since the question can be interpreted multiple ways, I think the question is probably at fault here. Until the question is clarified, I think it should be placed on hold.
The simplest and fastest way to do this is with a slice:
print(my_list[::2]) # Slice the whole list, with step=2
To replicate the logic you're describing, where you want to take the values with indexes that are modulo 2, then you need to generate both the indexes and the values for your list in the comprehension, and use one for the filtering and the other for the result:
hi = [ch for ix, ch in enumerate(my_list) if ix % 2 == 0]
Python strings have islower method. Also, you can directly iterate over the list, no need to check its length or the parity of the indexes.
my_list = ['a', 'A', 'b', 'B', 'c', 'C', 'd', 'D']
hi = [char for char in my_list if char.islower()]
print(hi)
# ['a', 'b', 'c', d']
Your list comprehension:
[char for char in range(len(my_list)) if char%2 == 0]
Will produce integers instead of characters. This is because range(len(my_list)) gives you indices. You instead need to get the characters.
This can be done using enumerate():
[char for i, char in enumerate(my_list) if i % 2 == 0]
Or a less pythonic approach, using just indexing my_list:
[my_list[i] for i in range(len(my_list)) if i % 2 == 0]
You can also just filter out the lowercase letters with str.islower():
[char for char in my_list if char.islower()]
Which avoids having to use indices altogether.
You can use list comprehension as following where you iterate over your individual elements and check if it is a lower case using .islower()
my_list = ['a', 'A', 'b', 'B', 'c', 'C', 'd', 'D']
lower = [i for i in my_list if i.islower()]
# ['a', 'b', 'c', 'd']
my_list = ['a', 'A', 'b', 'B', 'c', 'C', 'd', 'D']
res = [ char for char in my_list if ord(char)>=97]
using islower() function
l = ['a', 'A', 'b', 'B', 'c', 'C', 'd', 'D']
result = [el for el in l if el.islower()]
To add a range(len(my_list)) that create the following range(0, 8)
and char, in this case, is an integer and you create a list of integers.
To generate a list with only the lowercase letters use 'islower' method
hi = ([ char for char in my_list if char.islower()])

Python 3 sort list -> all entries starting with lower case first

l1 = ['B','c','aA','b','Aa','C','A','a']
the result should be
['a','aA','b','c','A','Aa','B','C']
so same as l1.sort() but beginning with all words that start with lower case.
Try this:
>>> l = ['B', 'b','a','A', 'aA', 'Aa','C', 'c']
>>> sorted(l, key=str.swapcase)
['a', 'aA', 'b', 'c', 'A', 'Aa', 'B', 'C']
EDIT:
A one-liner using the list.sort method for those who prefer the imperative approach:
>>> l.sort(key=str.swapcase)
>>> print l
['a', 'aA', 'b', 'c', 'A', 'Aa', 'B', 'C']
Note:
The first approach leaves the state of l unchanged while the second one does change it.
Here is what you might be looking for:
li = ['a', 'A', 'b', 'B']
def sort_low_case_first(li):
li.sort() # will sort the list, uppercase first
index = 0 # where the list needs to be cuted off
for i, x in enumerate(li): # iterate over the list
if x[0].islower(): # if we uncounter a string starting with a lowercase
index = i # memorize where
break # stop searching
return li[index:]+li[:index] # return the end of the list, containing the sorted lower case starting strings, then the sorted uppercase starting strings
sorted_li = sort_low_case_first(li) # run the function
print(sorted_li) # check the result
>>> ['a', 'b', 'A', 'B']

Compare 2 lists and return index and value to a third list

answer_list = ['a', 'b', 'c', 'd']
student_answers = ['a', 'c', 'b', 'd']
incorrect = []
I want to compare index 0 in list1 to index 0 in list2 and, if they are equal, move to compare index 1 in each list.
In this instance index 1 in list1 != index 1 in list 2 so I want to append index+1 and the incorrect student answer (in this case the letter c) to the empty list. This is what I tried - unsuccessfully.
def main():
list1 = ['a', 'b', 'c', 'd']
list2 = ['a', 'c', 'b', 'd']
incorrect = []
for x in list1:
for y in list2:
if x != y:
incorrect.append(y)
print(incorrect)
main()
Since you need to compare lists element-by-element, you also need to iterate over those list simultaneously. There is more than one way to do this, here are a few.
Built-in function zip allows you to iterate over multiple iterable objects. This would be my method of choice because, in my opinion, it's the easiest and the most readable way to iterate over several sequences all at once.
for x,y in zip(list1, list2):
if x != y:
incorrect.append(y)
The other way would be to use method enumerate:
for pos, value in enumerate(list1):
if value != list2[pos]:
incorrect.append(list2[pos])
Enumerate takes care of keeping track of indexing for you, so you don't need to create a special counter just for that.
The third way is to iterate over lists using index. One way to do this is to write:
for pos range(len(list1)):
if list1[pos] != list2[pos]:
incorrect.append(list2[pos])
Notice how by using enumerate you can get index out-of-the-box.
All of those methods can also be written using list comprehensions, but in my opinion, this is more readable.
You can use enumerate and list comprehension to check the index comparison.
answer_list = ['a', 'b', 'c', 'd']
student_answers = ['a', 'c', 'b', 'd']
incorrect = [y for x,y in enumerate(answer_list) if y != student_answers[x]]
incorrect
['b', 'c']
If you want the indexes that don't match and the values:
incorrect = [[y,answer_list.index(y)] for x,y in enumerate(answer_list) if y != student_answers[x]]
[['b', 1], ['c', 2]]
In x,y in enumerate(answer_list), the x is the index of the element and y is the element itself, so checking if y != student_answers[x] is comparing the elements at the same index in both lists. If they don't match, the element y is added to our list.
Using a loop similar to your own:
def main():
list1 = ['a', 'b', 'c', 'd']
list2 = ['a', 'c', 'b', 'd']
incorrect = []
for x,y in enumerate(list1):
if list2[x] != y:
incorrect.append(y)
print(incorrect)
In [20]: main()
['b', 'c']
To get element and index:
def main():
list1 = ['a', 'b', 'c', 'd']
list2 = ['a', 'c', 'b', 'd']
incorrect = []
for x,y in enumerate(list1):
if list2[x] != y:
incorrect.append([y,list1.index(y)])
print(incorrect)
In [2]: main()
[['b', 1], ['c', 2]]

How do I write "for item in list not in other_list" in one line using Python?

I want to make a loop for items in list that are not present in other_list, in one line. Something like this:
>>> list = ['a', 'b', 'c', 'd']
>>> other_list = ['a', 'd']
>>> for item in list not in other_list:
... print item
...
b
c
How is this possible?
for item in (i for i in my_list if i not in other_list):
print item
Its a bit more verbose, but its just as efficient, as it only renders each next element on the following loop.
Using set (which might do more than what you actually want to do) :
for item in set(list)-set(other_list):
print item
A third option: for i in filter(lambda x: x not in b, a): print(i)
list comprehension is your friend
>>> list = ['a', 'b', 'c', 'd']
>>> other_list = ['a', 'd']
>>> [x for x in list if x not in other_list]
['b', 'c']
also dont name things "list"

Python: if element in one list, change element in other?

I have two lists (of different lengths). One changes throughout the program (list1), the other (longer) doesn't (list2). Basically I have a function that is supposed to compare the elements in both lists, and if an element in list1 is in list2, that element in a copy of list2 is changed to 'A', and all other elements in the copy are changed to 'B'. I can get it to work when there is only one element in list1. But for some reason if the list is longer, all the elements in list2 turn to B....
def newList(list1,list2):
newList= list2[:]
for i in range(len(list2)):
for element in list1:
if element==newList[i]:
newList[i]='A'
else:
newList[i]='B'
return newList
Try this:
newlist = ['A' if x in list1 else 'B' for x in list2]
Works for the following example, I hope I understood you correctly? If a value in B exists in A, insert 'A' otherwise insert 'B' into a new list?
>>> a = [1,2,3,4,5]
>>> b = [1,3,4,6]
>>> ['A' if x in a else 'B' for x in b]
['A', 'A', 'A', 'B']
It could be because instead of
newList: list2[:]
you should have
newList = list2[:]
Personally, I prefer the following syntax, which I find to be more explicit:
import copy
newList = copy.copy(list2) # or copy.deepcopy
Now, I'd imagine part of the problem here is also that you use the same name, newList, for both your function and a local variable. That's not so good.
def newList(changing_list, static_list):
temporary_list = static_list[:]
for index, content in enumerate(temporary_list):
if content in changing_list:
temporary_list[index] = 'A'
else:
temporary_list[index] = 'B'
return temporary_list
Note here that you have not made it clear what to do when there are multiple entries in list1 and list2 that match. My code marks all of the matching ones 'A'. Example:
>>> a = [1, 2, 3]
>>> b = [3,4,7,2,6,8,9,1]
>>> newList(a,b)
['A', 'B', 'B', 'A', 'B', 'B', 'B', 'A']
I think this is what you want to do and can put newLis = list2[:] instead of the below but prefer to use list in these cases:
def newList1(list1,list2):
newLis = list(list2)
for i in range(len(list2)):
if newLis[i] in list1:
newLis[i]='A'
else: newLis[i]='B'
return newLis
The answer when passed
newList1(range(5),range(10))
is:
['A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B']

Categories

Resources