Python 3 turn range to a list - python

I'm trying to make a list with numbers 1-1000 in it. Obviously this would be annoying to write/read, so I'm attempting to make a list with a range in it. In Python 2 it seems that:
some_list = range(1,1000)
would have worked, but in Python 3 the range is similar to the xrange of Python 2?
Can anyone provide some insight into this?

You can just construct a list from the range object:
my_list = list(range(1, 1001))
This is how you do it with generators in python2.x as well. Typically speaking, you probably don't need a list though since you can come by the value of my_list[i] more efficiently (i + 1), and if you just need to iterate over it, you can just fall back on range.
Also note that on python2.x, xrange is still indexable1. This means that range on python3.x also has the same property2
1print xrange(30)[12] works for python2.x
2The analogous statement to 1 in python3.x is print(range(30)[12]) and that works also.

In Pythons <= 3.4 you can, as others suggested, use list(range(10)) in order to make a list out of a range (In general, any iterable).
Another alternative, introduced in Python 3.5 with its unpacking generalizations, is by using * in a list literal []:
>>> r = range(10)
>>> l = [*r]
>>> print(l)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Though this is equivalent to list(r), it's literal syntax and the fact that no function call is involved does let it execute faster. It's also less characters, if you need to code golf :-)

in Python 3.x, the range() function got its own type. so in this case you must use iterator
list(range(1000))

The reason why Python3 lacks a function for directly getting a ranged list is because the original Python3 designer was quite novice in Python2. He only considered the use of range() function in a for loop, thus, the list should never need to be expanded. In fact, very often we do need to use the range() function to produce a list and pass into a function.
Therefore, in this case, Python3 is less convenient as compared to Python2 because:
In Python2, we have xrange() and range();
In Python3, we have range() and list(range())
Nonetheless, you can still use list expansion in this way:
[*range(N)]

You really shouldn't need to use the numbers 1-1000 in a list. But if for some reason you really do need these numbers, then you could do:
[i for i in range(1, 1001)]
List Comprehension in a nutshell:
The above list comprehension translates to:
nums = []
for i in range(1, 1001):
nums.append(i)
This is just the list comprehension syntax, though from 2.x. I know that this will work in python 3, but am not sure if there is an upgraded syntax as well
Range starts inclusive of the first parameter; but ends Up To, Not Including the second Parameter (when supplied 2 parameters; if the first parameter is left off, it'll start at '0')
range(start, end+1)
[start, start+1, .., end]

Python 3:
my_list = [*range(1001)]

Actually, if you want 1-1000 (inclusive), use the range(...) function with parameters 1 and 1001: range(1, 1001), because the range(start, end) function goes from start to (end-1), inclusive.

Use Range in Python 3.
Here is a example function that return in between numbers from two numbers
def get_between_numbers(a, b):
"""
This function will return in between numbers from two numbers.
:param a:
:param b:
:return:
"""
x = []
if b < a:
x.extend(range(b, a))
x.append(a)
else:
x.extend(range(a, b))
x.append(b)
return x
Result
print(get_between_numbers(5, 9))
print(get_between_numbers(9, 5))
[5, 6, 7, 8, 9]
[5, 6, 7, 8, 9]

In fact, this is a retro-gradation of Python3 as compared to Python2. Certainly, Python2 which uses range() and xrange() is more convenient than Python3 which uses list(range()) and range() respectively. The reason is because the original designer of Python3 is not very experienced, they only considered the use of the range function by many beginners to iterate over a large number of elements where it is both memory and CPU inefficient; but they neglected the use of the range function to produce a number list. Now, it is too late for them to change back already.
If I was to be the designer of Python3, I will:
use irange to return a sequence iterator
use lrange to return a sequence list
use range to return either a sequence iterator (if the number of elements is large, e.g., range(9999999) or a sequence list (if the number of elements is small, e.g., range(10))
That should be optimal.

Related

What is the reason for removing default values of start and step in range() function in Python3?

I am learning Python3 and as I can see in the past, with Python2, it was possible to create a list of numbers with range() by just passing a single argument, which would be the last number of list + 1 in the list:
range(4) # == [0, 1, 2, 3]
and the start and step values were defaulted to 0 and 1.
But in Python3 for some reason, it is no longer possible to omit those 2 arguments and for the same result we would need to wrap the range() function with the list() function:
range(0, 4, 1) # == range(0, 4)
range(4) # == range(0, 4)
list(range(4)) # == [0, 1, 2, 3]
Question(s):
What is the reason behind that? Why was the functionality changed this way? Is there a good reason for that?
P.S. or maybe I am doing something incorrectly. Here, I am talking about range() function in general, whether it is being used in for-loops, just to create a list or for any other purpose
You've unfortunately been misled by the repr of range:
>>> range(4)
range(0, 4)
It is actually the same interface, but this is returning a lazily-generated sequence now, as opposed to a list. You may iterate a range instance to consume the values:
>>> list(range(4))
[0, 1, 2, 3]
See Python range() and zip() object type for more details about this change.

lambda with condition in Python

Any way to improve the code with a better solution?
say in the list nums = [1, 2, 3, 4, 5, 6], want to use lambda to do a simple calculation for num%2 == 0 only as the following:
print map(lambda n:n**2, filter(lambda n: n%2!=0, nums))
Just wonder if any way to just use one lambda expression for it?
If you really want to use lambda, you can do it with one lambda that issues the squared value or 0 depending on the oddness of the input, using a ternary expression (but you still have to filter using None so only non-zero numbers are kept)
nums = [1, 2, 3, 4, 5, 6]
result = list(filter(None,map(lambda n:n**2 if n%2 else 0,nums)))
result:
[1, 9, 25]
note that list conversion is required only for python 3.
Of course, all those filter, map, ... chaining renders the lambda inefficient/not that useful. You'd be better off with a simple list comprehension.
result = [n**2 for n in nums if n%2]
map should be only needed when you have the function (or built-in) handy (like map(str,my_list) for instance). All those chained calls could be less performant than that simple list comprehension in the end.
A more detailed explanation here: https://docs.python.org/2/howto/functional.html#small-functions-and-the-lambda-expression
Which alternative is preferable? That’s a style question; my usual course is to avoid using lambda.
One reason for my preference is that lambda is quite limited in the functions it can define. The result has to be computable as a single expression, which means you can’t have multiway if... elif... else comparisons or try... except statements. If you try to do too much in a lambda statement, you’ll end up with an overly complicated expression that’s hard to read.

Accessing a list given a condition on another list in Python

I want to access the elements of a list given a condition on another list. Normally, I would do this by using NumPy, but the requirements I have to follow state that I have to stick to Python Standard Library. An example of my problem is the following:
x = [1, 7, 11, 8, 13, 2]
y = [0,3,0,5,2]
#NumPy notation
z = x[y==0]
I have come up with a solution by using a list comprehension:
z = [x[i] for i in xrange(len(y)) if y[i] == 0]
However, it is quite slower in comparison to my implementation in NumPy. Is there any better way to address this?
EDIT: I have not mentioned but my requirements include the use of python 2
You can zip() the items together:
try:
# iterator zip from Python 3
from future_builtins import zip
except ImportError:
# this *is* Python 3
pass
z = [xval for xval, yval in zip(x, y) if yval == 0]
This also avoids building a list for the zip() even when using Python 2.
I'd personally use iterators and zip (if one list is shorter, it will be quicker)
That way I avoid the double access to elements and I don't have exception if a list is shorter than the other (you should use in xrange(min(len(x),len(y)))
[a for (a,b) in zip(x,y) if b==0]
Note that zip is iterator for python 3, not for python 2
I haven't benchmarked though

Is a Python list guaranteed to have its elements stay in the order they are inserted in?

If I have the following Python code
>>> x = []
>>> x = x + [1]
>>> x = x + [2]
>>> x = x + [3]
>>> x
[1, 2, 3]
Will x be guaranteed to always be [1,2,3], or are other orderings of the interim elements possible?
Yes, the order of elements in a python list is persistent.
In short, yes, the order is preserved. In long:
In general the following definitions will always apply to objects like lists:
A list is a collection of elements that can contain duplicate elements and has a defined order that generally does not change unless explicitly made to do so. stacks and queues are both types of lists that provide specific (often limited) behavior for adding and removing elements (stacks being LIFO, queues being FIFO). Lists are practical representations of, well, lists of things. A string can be thought of as a list of characters, as the order is important ("abc" != "bca") and duplicates in the content of the string are certainly permitted ("aaa" can exist and != "a").
A set is a collection of elements that cannot contain duplicates and has a non-definite order that may or may not change over time. Sets do not represent lists of things so much as they describe the extent of a certain selection of things. The internal structure of set, how its elements are stored relative to each other, is usually not meant to convey useful information. In some implementations, sets are always internally sorted; in others the ordering is simply undefined (usually depending on a hash function).
Collection is a generic term referring to any object used to store a (usually variable) number of other objects. Both lists and sets are a type of collection. Tuples and Arrays are normally not considered to be collections. Some languages consider maps (containers that describe associations between different objects) to be a type of collection as well.
This naming scheme holds true for all programming languages that I know of, including Python, C++, Java, C#, and Lisp (in which lists not keeping their order would be particularly catastrophic). If anyone knows of any where this is not the case, please just say so and I'll edit my answer. Note that specific implementations may use other names for these objects, such as vector in C++ and flex in ALGOL 68 (both lists; flex is technically just a re-sizable array).
If there is any confusion left in your case due to the specifics of how the + sign works here, just know that order is important for lists and unless there is very good reason to believe otherwise you can pretty much always safely assume that list operations preserve order. In this case, the + sign behaves much like it does for strings (which are really just lists of characters anyway): it takes the content of a list and places it behind the content of another.
If we have
list1 = [0, 1, 2, 3, 4]
list2 = [5, 6, 7, 8, 9]
Then
list1 + list2
Is the same as
[0, 1, 2, 3, 4] + [5, 6, 7, 8, 9]
Which evaluates to
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Much like
"abdcde" + "fghijk"
Produces
"abdcdefghijk"
You are confusing 'sets' and 'lists'. A set does not guarantee order, but lists do.
Sets are declared using curly brackets: {}. In contrast, lists are declared using square brackets: [].
mySet = {a, b, c, c}
Does not guarantee order, but list does:
myList = [a, b, c]
I suppose one thing that may be concerning you is whether or not the entries could change, so that the 2 becomes a different number, for instance. You can put your mind at ease here, because in Python, integers are immutable, meaning they cannot change after they are created.
Not everything in Python is immutable, though. For example, lists are mutable---they can change after being created. So for example, if you had a list of lists
>>> a = [[1], [2], [3]]
>>> a[0].append(7)
>>> a
[[1, 7], [2], [3]]
Here, I changed the first entry of a (I added 7 to it). One could imagine shuffling things around, and getting unexpected things here if you are not careful (and indeed, this does happen to everyone when they start programming in Python in some way or another; just search this site for "modifying a list while looping through it" to see dozens of examples).
It's also worth pointing out that x = x + [a] and x.append(a) are not the same thing. The second one mutates x, and the first one creates a new list and assigns it to x. To see the difference, try setting y = x before adding anything to x and trying each one, and look at the difference the two make to y.
Yes the list will remain as [1,2,3] unless you perform some other operation on it.
aList=[1,2,3]
i=0
for item in aList:
if i<2:
aList.remove(item)
i+=1
aList
[2]
The moral is when modifying a list in a loop driven by the list, takes two steps:
aList=[1,2,3]
i=0
for item in aList:
if i<2:
aList[i]="del"
i+=1
aList
['del', 'del', 3]
for i in range(2):
del aList[0]
aList
[3]
Yes lists and tuples are always ordered while dictionaries are not

Python Permutation code

Started to learn programming 2 months ago, in one of my little projects i encountered the need to generate permutations of list of objects.
I knew that i'll find how to do this if i'll just searched for it, but i wanted to make one of my own, so i worked up and made my own permutation generator code:
def perm(lst, c = [], x = 0):
i = -1
g = len(lst) - 1
if x == g:
while i < g:
i += 1
if lst[i] in c:
continue
c.append(lst[i])
print(c)
del c[-1]
i = g
else:
while i < g:
if x == 0:
del c[:]
elif g == x:
del c[-1]
elif len(c) > x:
del c[-1]
continue
i += 1
if lst[i] in c:
continue
c.append(lst[i])
x + 1
perm(lst, c, x + 1)
This is what it gives if i run it:
perm(range(2))
[0, 1]
[1, 0]
perm([1, 4, 5])
[1, 4, 5]
[1, 5, 4]
[4, 1, 5]
[4, 5, 1]
[5, 1, 4]
[5, 4, 1]
It works as i expected, but when i use bigger lists it take some time for it to generate all the permutations of the list.
So all i want is hints on how to improve my code, only hints.
Or if you can tell me what should i learn to be able to make a better generator?
Thanks in advance for all the helpers.
Generating permutations is often done recursively. Given a list of 5 items, the permutations can be created by picking each of the 5 elements in turn as the first element of the answer, then for each of them permuting the remaining 4 elements, and appending them together.
>>> from itertools import permutations
>>> list(permutations(range(2)))
[(0, 1), (1, 0)]
>>> list(permutations([1, 4, 5]))
[(1, 4, 5), (1, 5, 4), (4, 1, 5), (4, 5, 1), (5, 1, 4), (5, 4, 1)]
In the docs there is Python code available for legacy versions.
A note re your code, x + 1 doesn't do anything as you're not assigning result of that expression to anyting.
The best way to understand what is making your code slow is to actually measure it. When you attempt to guess at what will make something fast, it's often wrong. You've got the right idea in that you're noticing that your code is slower and it's time for some improvement.
Since this is a fairly small piece of code, the timeit module will probably be useful. Break the code up into sections, and time them. A good rule of thumb is that it's better to look at an inner loop for improvements, since this will be executed the most times. In your example, this would be the loop inside the perm function.
It is also worth noting that while loops are generally slower than for loops in python, and that list comprehensions are faster than both of these.
Once you start writing longer scripts, you'll want to be aware of the ability to profile in python, which will help you identify where your code is slow. Hopefully this has given you a few places to look.
OK, for large lists, a recursive solution will take more and more time & space, and eventually reach the recursion limit and die. So, on the theoretical side, you could work on ways to save time and space.
Hint: tail-recursive functions (such as the one you've written) can be rewritten as loops
On a more practical side, you may consider the use cases of your function. Maybe there's somebody who doesn't want the whole list of permutations at once, but a single one each time - there's a good opportunity to learn about yield and generators.
Also, for something generally not directly applicable to your question: k-combinations and multisets are closely related to permutations. Perhaps you can extend your function (or write a new one) which will produce the k-combinations and/or multiset the user asks for.
The first thing I notice is that the code is hard to understand. The variable names are completely meaningless, replace them with meaningful names. It also seems like you're using i as a loop index, which is almost always bad style in python, because you can do for item in list:.
This is not really performance related, but there is a glaring bug in the code. Using a list as a default parameter does not do what you think it does - it will create one list object that will be shared by every call to perm(), so the second time you call perm you will have the value in c of whatever it contained when the last call finished. This is a common beginner's error.
You also say "when I use bigger lists it takes some time to generate all the permutations of the list". What did you expect? The number of permutations is equal to the factorial of the length of the list, and that grows big fast! For example a list of length 20 will have 2432902008176640000 permutations. Even the most efficient algorithm in the world is "going to take some time" for a list this size, even if it did not run out of memory first. If our hypothetical algorithm generated a billion permutations a second it would still take 77 years to run. Can you be more specific about the length of lists you are using and how long it is taking?

Categories