Given a list
a = range(10)
You can slice it using statements such as
a[1]
a[2:4]
However, I want to do this based on a variable set elsewhere in the code. I can easily do this for the first one
i = 1
a[i]
But how do I do this for the other one? I've tried indexing with a list:
i = [2, 3, 4]
a[i]
But that doesn't work. I've also tried using a string:
i = "2:4"
a[i]
But that doesn't work either.
Is this possible?
that's what slice() is for:
a = range(10)
s = slice(2,4)
print a[s]
That's the same as using a[2:4].
Why does it have to be a single variable? Just use two variables:
i, j = 2, 4
a[i:j]
If it really needs to be a single variable you could use a tuple.
With the assignments below you are still using the same type of slicing operations you show, but now with variables for the values.
a = range(10)
i = 2
j = 4
then
print a[i:j]
[2, 3]
>>> a=range(10)
>>> i=[2,3,4]
>>> a[i[0]:i[-1]]
range(2, 4)
>>> list(a[i[0]:i[-1]])
[2, 3]
I ran across this recently, while looking up how to have the user mimic the usual slice syntax of a:b:c, ::c, etc. via arguments passed on the command line.
The argument is read as a string, and I'd rather not split on ':', pass that to slice(), etc. Besides, if the user passes a single integer i, the intended meaning is clearly a[i]. Nevertheless, slice(i) will default to slice(None,i,None), which isn't the desired result.
In any case, the most straightforward solution I could come up with was to read in the string as a variable st say, and then recover the desired list slice as eval(f"a[{st}]").
This uses the eval() builtin and an f-string where st is interpolated inside the braces. It handles precisely the usual colon-separated slicing syntax, since it just plugs in that colon-containing string as-is.
Related
For example, why is a not equal to b?
a = [1]
a.append(2)
print(a) # [1, 2]
b = [1].append(2)
print(b) # None
The syntax for b doesn't look wrong to me, but it is. I want to write one-liners to define a list (e.g. using a generator expression) and then append elements, but all I get is None.
It's because:
append, extend, sort and more list function are all "in-place".
What does "in-place" mean? it means it modifies the original variable directly, some things you would need:
l = sorted(l)
To modify the list, but append already does that, so:
l.append(3)
Will modify l already, don't need:
l = l.append(3)
If you do:
l = [1].append(2)
Yes it will modify the list of [1], but it would be lost in memory somewhere inaccessible, whereas l will become None as we discovered above.
To make it not "in-place", without using append either do:
l = l + [2]
Or:
l = [*l, 2]
The one-liner for b does these steps:
Defines a list [1]
Appends 2 to the list in-place
Append has no return, so b = None
The same is true for all list methods that alter the list in-place without a return. These are all None:
c = [1].extend([2])
d = [2, 1].sort()
e = [1].insert(1, 2)
...
If you wanted a one-liner that is similar to your define and extend, you could do
c2 = [1, *[2]]
which you could use to combine two generator expressions.
All built-in methods under class 'List' in Python are just modifying the list 'in situ'. They only change the original list and return nothing.
The advantage is, you don't need to pass the object to the original variable every time you modify it. Meanwhile, you can't accumulatively call its methods in one line of code such as what is used in Javascript. Because Javascript always turns its objects into DOM, but Python not.
This question already has answers here:
Modifying a list while iterating when programming with python [duplicate]
(5 answers)
Closed 4 years ago.
I am trying to reverse a list using append and remove method. But there is a problem in my method of doing this solution. Perhaps anyone give me a better explanation
list_in_order = [1,2,3,4,5,6]
def reverse(list):
r=[]
for i in list:
print (i)
r.append(i)
list_in_order.remove(i)
return r
print(reverse(list_in_order))
You can't use list.append, as that appends to the end of the list. What you want is to append to the start of the list. For that use list.insert. For more details see the list docs.
list_in_order = [1,2,3,4,5,6]
def reverse(L):
r = []
for i in L:
r.insert(0, i)
return r
print(reverse(list_in_order))
The other option is of course to use slice notation.
>>> [1,2,3,4,5,6][::-1]
[6, 5, 4, 3, 2, 1]
To make some constructive criticisms of the code in your question
Don't refer to variables outside of the function, unless you really intend to use globals. list_in_order.remove(i) refers to your global variable, not your function argument (although they ultimately refer to the same thing in this case). It may have been a typo but its worth pointing out that it's not quite right.
Don't use variable names that hide built in types. list, dict, tuple, set etc... These are not good names for variables as they will hide those types from further use in the scope that variable exists in and it may be difficult to find the source of the errors you get as a result.
Make your functions do one of two things; either modify the input (called in place modification) and return None or create a new collection and return that.
Don't iterate over a collection while modifying it. See linked dupe for elaboration.
In [11]: list_in_order = [1,2,3,4,5,6]
In [12]: list(reversed(list_in_order))
Out[12]: [6, 5, 4, 3, 2, 1]
Do you want [6, 5, 4, 3, 2, 1] for the result?
If so, just use list_in_order[::-1]
If you must use the append and remove,
list_in_order = [1,2,3,4,5,6]
def reverse_list(target_list):
copied_list = target_list.copy()
r=[]
for i in reversed(target_list):
r.append(i)
copied_list.remove(i)
return r
don't remove list elements when it in loop.
don't use 'list' for variable/parameter name.
I would make it like this :
list_in_order = [1,2,3,4,5,6]
def reverse(list):
counter = len(list)
for i in range(0,counter/2):
print(i)
list[i],list[counter-i] = list[counter-i], list[i]
return list
print(reverse(list_in_order))
This is a one way to do it, but you can do it using a recursion :)
Let's say I have a string
str1 = "TN 81 NZ 0025"
two = first2(str1)
print(two) # -> TN
How do I get the first two letters of this string? I need the first2 function for this.
It is as simple as string[:2]. A function can be easily written to do it, if you need.
Even this, is as simple as
def first2(s):
return s[:2]
In general, you can get the characters of a string from i until j with string[i:j].
string[:2] is shorthand for string[0:2]. This works for lists as well.
Learn about Python's slice notation at the official tutorial
t = "your string"
Play with the first N characters of a string with
def firstN(s, n=2):
return s[:n]
which is by default equivalent to
t[:2]
Heres what the simple function would look like:
def firstTwo(string):
return string[:2]
In python strings are list of characters, but they are not explicitly list type, just list-like (i.e. it can be treated like a list). More formally, they're known as sequence (see http://docs.python.org/2/library/stdtypes.html#sequence-types-str-unicode-list-tuple-bytearray-buffer-xrange):
>>> a = 'foo bar'
>>> isinstance(a, list)
False
>>> isinstance(a, str)
True
Since strings are sequence, you can use slicing to access parts of the list, denoted by list[start_index:end_index] see Explain Python's slice notation . For example:
>>> a = [1,2,3,4]
>>> a[0]
1 # first element, NOT a sequence.
>>> a[0:1]
[1] # a slice from first to second, a list, i.e. a sequence.
>>> a[0:2]
[1, 2]
>>> a[:2]
[1, 2]
>>> x = "foo bar"
>>> x[0:2]
'fo'
>>> x[:2]
'fo'
When undefined, the slice notation takes the starting position as the 0, and end position as len(sequence).
In the olden C days, it's an array of characters, the whole issue of dynamic vs static list sounds like legend now, see Python List vs. Array - when to use?
All previous examples will raise an exception in case your string is not long enough.
Another approach is to use
'yourstring'.ljust(100)[:100].strip().
This will give you first 100 chars.
You might get a shorter string in case your string last chars are spaces.
For completeness: Instead of using def you could give a name to a lambda function:
first2 = lambda s: s[:2]
I'm new to Python, the following output I'm getting from a simple list slice operation confused the jebuse out of me.
Here is the code.
>>> a = [1,2,3,4];
>>> a[1:3]
[2, 3]
>>> a[3]
4
shouldn't a[1:3] returns [2,3,4] instead of [2,3]?
a[1:3] specifies a half-closed interval, which means it includes the values starting at the 1st specified index up to, but not including, at the 2nd index.
So in this case a[1:3] means the slice includes a[1] and a[2], but not a[3]
You see the same in the use of the range() function. For instance
range(1, 5)
will generate a list from 1 to 4, but will not include 5.
This is pretty consistent with how things are done in many programming languages.
Slicing returns up to (but not including) the second slice index.
The docs for slice may help.
slice([start], stop[, step])
Return a slice object representing the
set of indices specified by range(start, stop, step).
The slice format that most of are familiar with is just a shorthand:
a[start:stop:step]
You've got some good answers about how it works, here's one with why:
a = '0123456789'
a[2:4]
'23'
a[4:6]
'45'
a[6:8]
'67'
IOW, it makes it easy to step through a list or string or tuple n characters at a time, without wasting time on the +1 / -1 stuff needed in most languages.
What am I doing wrong here?
a = set().add(1)
print a # Prints `None`
I'm trying to add the number 1 to the empty set.
It is a convention in Python that methods that mutate sequences return None.
Consider:
>>> a_list = [3, 2, 1]
>>> print a_list.sort()
None
>>> a_list
[1, 2, 3]
>>> a_dict = {}
>>> print a_dict.__setitem__('a', 1)
None
>>> a_dict
{'a': 1}
>>> a_set = set()
>>> print a_set.add(1)
None
>>> a_set
set([1])
Some may consider this convention "a horrible misdesign in Python", but the Design and History FAQ gives the reasoning behind this design decision (with respect to lists):
Why doesn’t list.sort() return the sorted list?
In situations where performance matters, making a copy of the list
just to sort it would be wasteful. Therefore, list.sort() sorts the
list in place. In order to remind you of that fact, it does not return
the sorted list. This way, you won’t be fooled into accidentally
overwriting a list when you need a sorted copy but also need to keep
the unsorted version around.
In Python 2.4 a new built-in function – sorted() – has been added.
This function creates a new list from a provided iterable, sorts it
and returns it.
Your particular problems with this feature come from a misunderstanding of good ways to create a set rather than a language misdesign. As Lattyware points out, in Python versions 2.7 and later you can use a set literal a = {1} or do a = set([1]) as per Sven Marnach's answer.
Parenthetically, I like Ruby's convention of placing an exclamation point after methods that mutate objects, but I find Python's approach acceptable.
The add() method adds an element to the set, but it does not return the set again -- it returns None.
a = set()
a.add(1)
or better
a = set([1])
would work.
Because add() is modifing your set in place returning None:
>>> empty = set()
>>> print(empty.add(1))
None
>>> empty
set([1])
Another way to do it that is relatively simple would be:
a = set()
a = set() | {1}
this creates a union between your set a and a set with 1 as the element
print(a) yields {1} then because a would now have all elements of both a and {1}
You should do this:
a = set()
a.add(1)
print a
Notice that you're assigning to a the result of adding 1, and the add operation, as defined in Python, returns None - and that's what is getting assigned to a in your code.
Alternatively, you can do this for initializing a set:
a = set([1, 2, 3])
The add method updates the set, but returns None.
a = set()
a.add(1)
print a
You are assigning the value returned by set().add(1) to a. This value is None, as add() does not return any value, it instead acts in-place on the list.
What you wanted to do was this:
a = set()
a.add(1)
print(a)
Of course, this example is trivial, but Python does support set literals, so if you really wanted to do this, it's better to do:
a = {1}
print(a)
The curly brackets denote a set (although be warned, {} denotes an empty dict, not an empty set due to the fact that curly brackets are used for both dicts and sets (dicts are separated by the use of the colon to separate keys and values.)
Alternatively to a = set() | {1} consider "in-place" operator:
a = set()
a |= {1}