There is: negative indices:
lst[-2]
Answer from Scott Hunter on Stack OverflowThe Python slice syntax is alist[start:end:step]. So, with your slice ::-1, you are just reversing the list.
If you want the second element to the last, the correct slice would be
alist[1:]
a = {}
for line in file_a.readlines():
split_line = line.strip().split('\t')
a[split_line[0]] = split_line[1:]
a = {}
for line in file_a:
split_line = line.strip().split('\t')
a[split_line[0]] = split_line[1:]
You slicing expression split_line[::-1] evaluates to split_line reversed, because the third parameter is the step (-1 in this case). You want to start at element 1 and go all the way to the end, with the default step of 1. Check this answer for more on slice notation.
python - How do I get the last element of a list? - Stack Overflow
python 3.x - i want to find the second last element in the list - Stack Overflow
-1 returns second to last item in python list - Stack Overflow
python - Find the second last number from a list - Stack Overflow
There is actually no need to use indices here, as Python loops allow to iterate over elements directly. Then, with simple list slicing you can take the range you want:
integers = [1,3,2,4]
for integer in integers[1:]:
print(integer)
Or, to iterate over elements instead of indexes, but avoid creating a new copy of the list (slices create a new list object), you can use islice:
from itertools import islice
for integer in islice(integers, 1, None):
print(integer)
The range() function
We can generate a sequence of numbers using range() function. range(10) will generate numbers from 0 to 9 (10 numbers). We can also define the start, stop and step size as
range(start,stop,step size). step size defaults to 1 if not provided. This function does not store all the values in memory, it would be inefficient. So it remembers the start, stop, step size and generates the next number on the go.
Your code should looks like:
integer = [1,3,2,4]
for i in range(1,len(integer)):
print (integer[i])
Output:
3
2
4
some_list[-1] is the shortest and most Pythonic.
In fact, you can do much more with this syntax. The some_list[-n] syntax gets the nth-to-last element. So some_list[-1] gets the last element, some_list[-2] gets the second to last, etc, all the way down to some_list[-len(some_list)], which gives you the first element.
You can also set list elements in this way. For instance:
>>> some_list = [1, 2, 3]
>>> some_list[-1] = 5 # Set the last element
>>> some_list[-2] = 3 # Set the second to last element
>>> some_list
[1, 3, 5]
Note that getting a list item by index will raise an IndexError if the expected item doesn't exist. This means that some_list[-1] will raise an exception if some_list is empty, because an empty list can't have a last element.
If your str() or list() objects might end up being empty as so: astr = '' or alist = [], then you might want to use alist[-1:] instead of alist[-1] for object "sameness".
The significance of this is:
alist = []
alist[-1] # will generate an IndexError exception whereas
alist[-1:] # will return an empty list
astr = ''
astr[-1] # will generate an IndexError exception whereas
astr[-1:] # will return an empty str
Where the distinction being made is that returning an empty list object or empty str object is more "last element"-like then an exception object.
You're giving input all at once in line number 5 - '2 3 6 6 5'.
Your code expects a single value at a time. Hence for n=5 you need to enter 5 values, one at a time, till your while loop is exhausted.
Solution:
arr=list(map(int, input().split()))
s=len(arr)
sorted(arr)
print(arr[-2])
You were entering a list of elements which were space separated. You don't need n at all. Just split the input and convert each entry to integer and store it in a list.
edit: forgot to mention I want the indeces not just the items
the methods I can think of are:
for i in range(len(arr) - 1)
for i, e in enumerate(arr[:len(arr) - 1])
I know range(len(arr)) is frowned upon, but I don't see how it's worse than enumerate in this case. In fact using enumerate on a shortened list and calling len to find the second to last element of that list seems extremely clunky and far less readable.
What's the best practice for doing this?
- You shouldn't change the
wordswhen you are iterating through it, otherwise it'll lead to some bugs. You need iterate the copy ofwordsto avoid changing it. - You remove the words when
word[0] == 'x', which cause the loop end before you want. - You can use debug mode in IDE(such as
VSCode,PyCharm) to run your code line by line to check what actually happened in runtime.
example code:
def front_x(words):
list2 = []
for word in words.copy():
if word[0] == 'x':
list2.append(word)
words.remove(word)
words.sort()
list2.sort()
return list2 + words
def main():
print(front_x(['bbb', 'ccc', 'axx', 'xzz', 'xaa']))
main()
result:
['xaa', 'xzz', 'axx', 'bbb', 'ccc']
This is because you are removing the element from the same list you are iterating . After removing an element from list , element position shift. When iteration pointer is on second last element list changes from ['bbb', 'ccc', 'axx', 'xzz', 'xaa'] to ['bbb', 'ccc', 'axx', 'xaa']. Thus iteration pointer now points to last element .
That's because you are specifying -1 as the index to go to - simply leave the index out to go to the end of the list. E.g:
input[1:]
See here for more on the list slicing syntax.
Note an alternative (which I feel is far nicer and more readable), if you are using Python 3.x, is to use extended iterable unpacking:
key, *values = input().split()
map[key] = values
myDict = {}
for line in lines:
tokens = line.split()
map[tokens[0]] = tokens[1:]
Alternatively:
def lineToPair(line):
tokens = line.split()
return tokens[0],tokens[1:]
myDict = dict(lineToPair(x) for x in lines)
list_a[-1] is the way to access the last element
You can use enumerate to iterate through both the items in the list, and the indices of those items.
for idx, item in enumerate(list_a):
if idx == len(list_a) - 1:
print item, "is the last"
else:
print item, "is not the last"
Result:
0 is not the last
1 is not the last
3 is not the last
1 is the last
An itertools approach with the building blocks broken out - get last elements, group into threes, convert groups of 3 into a list...
from operator import itemgetter
from itertools import imap, izip
last_element = imap(itemgetter(-1), a)
in_threes = izip(*[iter(last_element)] * 3)
res = map(list, in_threes)
# [[0, 3, 1], [2, 5, 2], [1, 2, 0], [0, 4, 2]]
However, it looks like you want to "group" on the first element (instead of purely blocks of 3 consecutive items), so you can use defaultdict for this:
from collections import defaultdict
dd = defaultdict(list)
for el in a:
dd[el[0]].append(el[-1])
# defaultdict(<type 'list'>, {100: [0, 3, 1], 101: [2, 5, 2], 102: [1, 2, 0], 103: [0, 4, 2]})
You are trying to do two things here:
- Get the last element of each nested list.
- Group those elements by the first element of each nested list.
You can use list comprehension to get the last element of each nested list:
last_elems = [sublist[-1] for sublist in outerlist]
If the whole list is sorted by the first element (the id) then you can use itertools.groupby to do the second part:
from itertools import groupby
from operator import itemgetter
[[g[-1] for g in group] for id_, group in groupby(outerlist, key=itemgetter(0))]
Demo:
>>> outerlist = [
... [100,'XHS',0],
... [100,'34B',3],
... [100,'42F',1],
... [101,'XHS',2],
... [101,'34B',5],
... [101,'42F',2],
... [102,'XHS',1],
... [102,'34B',2],
... [102,'42F',0],
... [103,'XHS',0],
... [103,'34B',4],
... [103,'42F',2]
... ]
>>> from itertools import groupby
>>> from operator import itemgetter
>>> [[g[-1] for g in group] for id_, group in groupby(outerlist, key=itemgetter(0))]
[[0, 3, 1], [2, 5, 2], [1, 2, 0], [0, 4, 2]]
If it wasn't sorted, you'd either have to sort it first (using outerlist.sort(key=itemgetter)), or, if you don't need a sorted version anywhere else, use a collections.defaultdict approach to grouping:
from collections import defaultdict
grouped = defaultdict(list)
for sublist in outerlist:
grouped[sublist[0]].append(sublist[-1])
output = grouped.values()
It's simply a matter of iterating over the list and reporting list[n-1] when list[n]>my_limit.
You will need to extend this to cope with edge cases (i.e. this will error if the first value is over the limit etc.)
And you might want to split your list into one list per commodity as this will trigger when commodities change too.
my_limit = 0.2
for n in range(1, len(my_list)):
value = float(my_list[n][2].replace(",", "."))
prev_value = float(my_list[n-1][2].replace(",", "."))
if value > my_limit and prev_value < my_limit:
print(my_list[n-1])
you can use the itertools module for this
>>> import itertools
>>> my_list = [
['Morocco', 'Fish', '0,012'],
['Morocco', 'Fish', '0,153'],
['Morocco', 'Fish', '0,114'],
['Morocco', 'Fish', '0,109'],
['Morocco', 'Fish', '0,252'],
['Spain', 'Fish', '0,012'],
['Spain', 'Fish', '0,113'],
['Spain', 'Fish', '0,116'],
['Spain', 'Fish', '0,250'],
['Spain', 'Fish', '0,266'],
['Italy', 'Fish', '0,112'],
['Italy', 'Fish', '0,025'],
['Italy', 'Fish', '0,224'],
['Italy', 'Fish', '0,256'],
['Italy', 'Fish', '0,245']]
>>> my_limit = 0.2
>>> for key,sublists in itertools.groupby(my_list,lambda y:y[0]):
v=[] #we initialize it in case no element fulfill the condition
for v in itertools.takewhile(lambda x:float(x[-1].replace(",","."))<my_limit ,sublists):
pass
if v:
print(v,"->",v[-1])
['Morocco', 'Fish', '0,109'] -> 0,109
['Spain', 'Fish', '0,116'] -> 0,116
['Italy', 'Fish', '0,025'] -> 0,025
>>>
here with groupby we, well, group together all the consecutive sublist that have the same value in a given position we specify, which in this case is the first position, then we go into those sublist and take those that fulfill our condition and stop at the first that doesn't with takewhile and from those we only want the last one which will stored into v at the end of the loop.
I make that grouping because that make more sense to my, but if grouping like that isn't necessary, we can also use groupby to split the list into the subsection that fulfill the condition and those that do not by changing the grouping key
>>> my_list = [
['Morocco', 'Fish', '0,012'],
['Morocco', 'Fish', '0,153'],
['Morocco', 'Fish', '0,114'],
['Morocco', 'Fish', '0,109'],
['Morocco', 'Fish', '0,252'],
['Morocco', 'Fish', '0,002'],#extra
['Morocco', 'Fish', '0,252'],#extra
['Spain', 'Fish', '0,012'],
['Spain', 'Fish', '0,113'],
['Spain', 'Fish', '0,116'],
['Spain', 'Fish', '0,250'],
['Spain', 'Fish', '0,266'],
['Spain', 'Fish', '0,066'], #extra
['Spain', 'Fish', '0,366'], #extra
['Italy', 'Fish', '0,112'],
['Italy', 'Fish', '0,025'],
['Italy', 'Fish', '0,224'],
['Italy', 'Fish', '0,256'],
['Italy', 'Fish', '0,245'],
['Italy', 'Fish', '0,005'],#extra
['Italy', 'Fish', '0,305']]#extra
>>> for condition,sublist in itertools.groupby(my_list,lambda x:float(x[-1].replace(",","."))<my_limit):
if condition:
for v in sublist:
pass
print(v,"->",v[-1])
['Morocco', 'Fish', '0,109'] -> 0,109
['Morocco', 'Fish', '0,002'] -> 0,002
['Spain', 'Fish', '0,116'] -> 0,116
['Spain', 'Fish', '0,066'] -> 0,066
['Italy', 'Fish', '0,025'] -> 0,025
['Italy', 'Fish', '0,005'] -> 0,005
>>>