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.
Related
I am doing some stuff in python, but I am not that used to it yet.
This is what I want the code to do (pseudocode):
if x in list or y in list but not x and y:
#do-stuff
the first part is correct (if x in list or y in list) but I don't know what to write after that. The but not x and ypart.
I'd probably go for using a set here instead...
if len({x, y}.intersection(your_list)) == 1:
# do something
This has the advantage that it only needs to iterate once over your_list.
Example:
examples = [
[1, 2, 3, 4, 5],
[2, 3, 4, 5, 6],
[100, 101, 102, 103, 104]
]
for example in examples:
overlap = {1, 5}.intersection(example)
print 'overlap is', overlap, 'with a length of', len(overlap)
# overlap is set([1, 5]) with a length of 2
# overlap is set([5]) with a length of 1
# overlap is set([]) with a length of 0
With "but" spelled and and a pair of parentheses, you can use:
x_in_list = x in list
y_in_list = y in list
if (x_in_list or y_in_list) and not (x_in_list and y_in_list):
...
Or, as suggested by behzad.nouri, use xor:
if (x in list) ^ (y in list):
...
This is shorter, but possibly less understandable to a non-CS-savvy reader.
Exclusive or means "one or the other, but not both" and maps perfectly in what you want to do:
if (x in list) ^ (y in list):
...
looks a bit weird because normally xor is only used for bitwise operations, but here works because Python will implicitly convert True and False to 1 and 0, making the operator work as expected in an if.
Note however that the parenthesis are necessary because the xor operator ^ has an higher precedence than in (it's most often used for bitwise math, so this choice is reasonable).
Inspired by Jon Clements's centi-upvoted answer,
items, it = {x, y}, (i in items for i in lst)
print(any(it) and not any(it))
This short-circuit version is better, in the negative cases.
it is an iterator of the original list, and we check if any of it is in items, if yes we check if all the other items are not in items.
Note: This works only if the items are unique in lst
In Python, how do I determine if an iterable has stable iteration order?
There's collections.Iterable abstract base class but there's no stable counterpart.
The reason I'm asking is to be able to prevent users or warn them when they pass (by mistake) iterable with unstable iteration order (dict, set, etc.) to a function where stability of iteration is crucial.
One thing you might be looking for is collections.Sequence. This is a bit more specific than what you want, since according to the docs a sequence "supports efficient element access using integer indices"; it's also not specific enough, since nothing explicitly guarantees that getting the same index twice has to return the same value both times. But this would suffice to distinguish lists and tuples from dicts and sets.
However, in general there is no way. In general there cannot be a way, because you can write any iterable you like and there's no requirement that you specify whether it's stable or not. E.g., you can do something like this:
>>> def f():
... if random.random() < 0.5:
... for a in xrange(10):
... yield a
... else:
... stuff = range(10)
... random.shuffle(stuff)
... for a in stuff:
... yield a
>>> list(f())
0: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(f())
1: [7, 0, 2, 8, 5, 1, 4, 3, 6, 9]
The fact that iterators can be written without having to declare whether they are stable or not, together with the fact that there isn't a way to tell by iterating over something whether it will iterate the same way later, means that there can be no way to tell if a given iterator is stable or not.
I would advise you to simply document that your function needs stability of iteration order. You can also explicitly check for builtin types that you know might not be stable, and raise an error on those. But there is no way to check in general for the stability of an arbitrary user-defined iterator's stability.
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.
After an hour of trying to understand the Y-Combinator... i finally got it, mostly but then i realized that the same thing can be achieved without it... although I'm not sure if i fully understand it's purpose.
eg. Factorials with Y-Combinator
print (lambda h: (lambda f:f(f))(lambda f: h(lambda n: f(f)(n))))(lambda g: lambda n: n and n * g(n-1) or 1)(input())
Factorials by haveing a reference to the function in another lambda
print (lambda f,m:f(f,m))((lambda g,n: n and n * g(g,n-1) or 1),input())
Can anybody please tell me if there is a purpose for the Y-Combinator in python?
The purpose of the Y combinator is to demonstrate how to write an arbitrary recursive function using only anonymous functions. But almost every language ever invented allows named functions! In other words, it is mainly of academic interest. Of course, you can define factorials much more "naturally" in Python:
def fac(n):
return n * fac(n-1) if n else 1
The only languages in which the Y combinator is actually useful in practice are the "Turing tarpit" languages, like Unlambda. Not even Lisp/Scheme users will typically use the Y combinator when writing real programs.
Python is not based on Lambda calculus; when you put the question this way it does not make much sense. The lambda statement is simply a practical feature to create an anonymous function inplace:
>>> list( map(lambda x: x**2, [1, 2, 3, 4, 5]) )
[1, 4, 9, 16, 25]
# the same as:
>>> def sq(x):
... return x**2
...
>>> list( map(sq, [1, 2, 3, 4, 5]) )
[1, 4, 9, 16, 25]
It is named this way because it was borrowed from functional languages, but it is not for computing with combinatory logic.
Normally, list comprehensions are used to derive a new list from an existing list. Eg:
>>> a = [1, 2, 3, 4, 5]
>>> [i for i in a if i > 2]
[3, 4, 5]
Should we use them to perform other procedures? Eg:
>>> a = [1, 2, 3, 4, 5]
>>> b = []
>>> [b.append(i) for i in a]
[None, None, None, None, None]
>>> print b
[1, 2, 3, 4, 5]
or should I avoid the above and use the following instead?:
for i in a:
b.append(i)
You should indeed avoid using list comprehensions (along with dictionary comprehensions, set comprehensions and generator expressions) for side effects. Apart from the fact that they'd accumulate a bogus list and thus waste memory, it's also confusing. I expect a list comprehension to generate a (meaningful) value, and many would agree. Loops, on the other hand, are clearly a sequence of statements. They are expected to kick off side effects and generate no result value - no surprise.
From python documentation:
List comprehensions provide a concise way to create lists. Common
applications are to make new lists
Perhaps you want to learn more about reduce(), filter() and map() functions.
In the example you give it would make the most sense to do:
b = [i for i in a]
if for some reason you wanted to create b. In general, there is some common sense that must be employed. If using a comprehension makes your code unreadable, don't use it. Otherwise go for it.
Only use list comprehensions if you plan to use the created list. Otherwise you create it just for the GC to throw it again without ever being used.
So instead of [b.append(i) for i in a] you should use a proper for loop:
for i in a:
b.append(i)
Another solution would be through a generator expression:
b += (i for i in a)
However, if you want to append the whole list, you can simply do
b += a
And if you just need to apply a function to the elements before adding them to the list, you can always use map:
b += map(somefunc, a)
b = []
a = [1, 2, 3, 4, 5]
b.extend (a)