Functional way to replace reduce() - python

In Python 3, reduce() has been moved to functools.reduce() and apparently it's better to use list comprehensions or plain loops for better readability.
I want to print the XOR'ed value of all elements in a list.
# My implementation with functools
from functools import reduce
print(reduce(lambda a, b: a^b, [1, 3, 2, 3, 4, 4, 5, 2, 1]))
And I have this:
# My implementation without functools
def XOR(x):
ans = 0
for i in x:
ans = ans ^ i
return ans
print(XOR([1, 3, 2, 3, 4, 4, 5, 2, 1]))
How can write a more functional version of this code without reduce()?
(Please provide references or code in Python 3, if any.)

Although Guido van Rossum didn't much care for reduce(), enough of the community did want it, which is why it was moved to functools and not removed outright. It is performant, and ideally suited to your use case. Just use it.
You can make your case faster and more readable by using operator.xor() to avoid the overhead of a new Python frame for a lambda:
from functools import reduce
from operator import xor
reduce(xor, [1, 3, 2, 3, 4, 4, 5, 2, 1])
Both xor() and reduce() are implemented in C. Calling back to the Python interpreter loop for the lambda is quite slow compared to calling another C function.
If you really must use a function, then use
def xor_reduce(values):
result = 0
for value in values:
result ^= value
return result
using in-place XOR, and better variable names.

Related

if i have a list of characters, how would i return its most two frequencies with the less time complexity?

I'm using python language.
The clear algorithm will be enough for me.
I've tried using a dictionary, and counting the existence of each character if it is not in the list.
But I'm not sure if it has the possible less complexity.
Use the in built Counter(list).most_common(n) method, as below.
from collections import Counter
input_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 5, 7, 3, 1]
most_common_values = [value[0] for value in Counter(input_list).most_common(2)]
print(most_common_values)
This outputs: [1, 2].
The advantages to this approach are that it is fast, simple, and returns a list of the items in order. In addition, if their is a 'tie' in value count, it will return the example that appears first, as displayed in the example above.
Use built-int Counter in collection library

Why sort and sorted functions are showing different results? [duplicate]

I am trying to sort a list by frequency of its elements.
>>> a = [5, 5, 4, 4, 4, 1, 2, 2]
>>> a.sort(key = a.count)
>>> a
[5, 5, 4, 4, 4, 1, 2, 2]
a is unchanged. However:
>>> sorted(a, key = a.count)
[1, 5, 5, 2, 2, 4, 4, 4]
Why does this method not work for .sort()?
What you see is the result of a certain CPython implementation detail of list.sort. Try this again, but create a copy of a first:
a.sort(key=a.copy().count)
a
# [1, 5, 5, 2, 2, 4, 4, 4]
.sort modifies a internally, so a.count is going to produce un-predictable results. This is documented as an implementation detail.
What copy call does is it creates a copy of a and uses that list's count method as the key. You can see what happens with some debug statements:
def count(x):
print(a)
return a.count(x)
a.sort(key=count)
[]
[]
[]
...
a turns up as an empty list when accessed inside .sort, and [].count(anything) will be 0. This explains why the output is the same as the input - the predicates are all the same (0).
OTOH, sorted creates a new list, so it doesn't have this problem.
If you really want to sort by frequency counts, the idiomatic method is to use a Counter:
from collections import Counter
a.sort(key=Counter(a).get)
a
# [1, 5, 5, 2, 2, 4, 4, 4]
It doesn't work with the list.sort method because CPython decides to "empty the list" temporarily (the other answer already presents this). This is mentioned in the documentation as implementation detail:
CPython implementation detail: While a list is being sorted, the effect of attempting to mutate, or even inspect, the list is undefined. The C implementation of Python makes the list appear empty for the duration, and raises ValueError if it can detect that the list has been mutated during a sort.
The source code contains a similar comment with a bit more explanation:
/* The list is temporarily made empty, so that mutations performed
* by comparison functions can't affect the slice of memory we're
* sorting (allowing mutations during sorting is a core-dump
* factory, since ob_item may change).
*/
The explanation isn't straight-forward but the problem is that the key-function and the comparisons could change the list instance during sorting which is very likely to result in undefined behavior of the C-code (which may crash the interpreter). To prevent that the list is emptied during the sorting, so that even if someone changes the instance it won't result in an interpreter crash.
This doesn't happen with sorted because sorted copies the list and simply sorts the copy. The copy is still emptied during the sorting but there's no way to access it, so it isn't visible.
However you really shouldn't sort like this to get a frequency sort. That's because for each item you call the key function once. And list.count iterates over each item, so you effectively iterate the whole list for each element (what is called O(n**2) complexity). A better way would be to calculate the frequency once for each element (can be done in O(n)) and then just access that in the key.
However since CPython has a Counter class that also supports most_common you could really just use that:
>>> from collections import Counter
>>> [item for item, count in reversed(Counter(a).most_common()) for _ in range(count)]
[1, 2, 2, 5, 5, 4, 4, 4]
This may change the order of the elements with equal counts but since you're doing a frequency count that shouldn't matter to much.

Python - mechanism of () and []

It looks e for e in [1, 2, 3, 4, 5] is a generator expression and (e for e in [1, 2, 3, 4, 5]) is evaluated as an generator object. Hence, I think (...) is evaluation in Python.
I suppose list(e for e in [1, 2, 3, 4, 5]) is telling the Python runtime to evaluate the iterable expression, generate its object(s), and call the list function to invoke yield until it runs out of elements.
print(list(e for e in [1, 2, 3, 4, 5]))
---
[1, 2, 3, 4, 5]
Question
What actually is [...] in the code below and what is its mechanism? [ e for e in [1, 2, 3, 4, 5] ] generates a list object, hence I suppose it is a combination of an evaluation on e for e in [1, 2, 3, 4, 5] to create a generator object and invoking a call to the generator object. Is it a alias of a function call to list(...)?
print([ e for e in [1, 2, 3, 4, 5] ])
---
[1, 2, 3, 4, 5]
For the list access with a slice object, I suppose [1:3] is telling Python to evaluate the 1:3 expression to generate a slice object.
print([1,2,3][1:3])
print([1,2,3][slice(1,3,1)])
---
[2, 3]
[2, 3]
[(1:3)] fails because it tries to evaluate already evaluated 1:3?
print([1,2,3][(1:3)])
---
File "<ipython-input-167-c20e211025dc>", line 1
print([1,2,3][(1:3)])
^
SyntaxError: invalid syntax
[1, 2, 3, 4, 5] is a list literal.
value for item in iterable is a generator comprehension. list(value for item in iterable) would be calling the list() constructor with a generator, which of course just produces a list. For the purpose of reducing ambiguity, the generator comprehension cannot be used naked. But it can be used either inside a set of parentheses, or inside another expression, such as a parameter in a function call. A similar limitation applies to the := (walrus) operator added in Python 3.8.
[value for item in iterable] is a list comprehension. Note that Python treats this as an entirely separate syntactic construct.
The implementations are probably about the same, but as far as I'm aware the Python compiler detects the generator comprehension and the list comprehension separately while it processes the code, and the list comprehension is not defined as a subset/special case of either a generator comprehension or a list literal.
I'm pretty sure a similar thing applies to slice syntax - it's defined as its own syntax, specifically in the context of list indexing, and in no other context. lst[1:3] getting compiled into lst.__getitem__(slice(1, 3)) is part of the compilation process, and is not a general thing for the syntax 1:3 (as that's ambiguous).
In other words, if I remember correctly, lst[x:y:z] is a different syntactic construct from lst[x], as far as the Python compiler is concerned.
*The information in this post is based on my understanding and prior interaction with various methods in the CPython source code. I'm drawing some conclusions between the syntax, the compiler, and the compiled code that may not be valid.

recursive function python, create function that generates all numbers that have same sum N

I am trying to code a recursive function that generates all the lists of numbers < N who's sum equal to N in python
This is the code I wrote :
def fn(v,n):
N=5
global vvi
v.append(n) ;
if(len(v)>N):
return
if(sum(v)>=5):
if(sum(v)==5): vvi.append(v)
else:
for i in range(n,N+1):
fn(v,i)
this is the output I get
vvi
Out[170]: [[1, 1, 1, 1, 1, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 4, 5]]
I tried same thing with c++ and it worked fine
What you need to do is to just formulate it as a recursive description and implement it. You want to prepend all singleton [j] to each of the lists with sum N-j, unless N-j=0 in which you also would include the singleton itself. Translated into python this would be
def glist(listsum, minelm=1):
for j in range(minelm, listsum+1):
if listsum-j > 0:
for l in glist(listsum-j, minelm=j):
yield [j]+l
else:
yield [j]
for l in glist(5):
print(l)
The solution contains a mechanism that will exclude permutated solutions by requiring the lists to be non-decreasing, this is done via the minelm argument that limits the values in the rest of the list. If you wan't to include permuted lists you could disable the minelm mechanism by replacing the recursion call to glist(listsum-j).
As for your code I don't really follow what you're trying to do. I'm sorry, but your code is not very clear (and that's not a bad thing only in python, it's actually more so in C).
First of all it's a bad idea to return the result from a function via a global variable, returning result is what return is for, but in python you have also yield that is nice if you want to return multiple elements as you go. For a recursive function it's even more horrible to return via a global variable (or even use it) since you are running many nested invocations of the function, but have only one global variable.
Also calling a function fn taking arguments v and n as argument. What do that actually tell you about the function and it's argument? At most that it's a function and probably that one of the argument should be a number. Not very useful if somebody (else) is to read and understand the code.
If you want an more elaborate answer what's formally wrong with your code you should probably include a minimal, complete, verifiable example including the expected output (and perhaps observed output).
You may want to reconsider the recursive solution and consider a dynamic programming approach:
def fn(N):
ways = {0:[[]]}
for n in range(1, N+1):
for i, x in enumerate(range(n, N+1)):
for v in ways[i]:
ways.setdefault(x, []).append(v+[n])
return ways[N]
>>> fn(5)
[[1, 1, 1, 1, 1], [1, 1, 1, 2], [1, 2, 2], [1, 1, 3], [2, 3], [1, 4], [5]]
>>> fn(3)
[[1, 1, 1], [1, 2], [3]]
Using global variables and side effects on input parameters is generally consider bad practice and you should look to avoid.

Python equivalent to Ruby Array.each method

In Python what is equivalent to Ruby's Array.each method? Does Python have a nice and short closure/lambda syntax for it?
[1,2,3].each do |x|
puts x
end
Does Python have a nice and short closure/lambda syntax for it?
Yes, but you don't want it in this case.
The closest equivalent to that Ruby code is:
new_values = map(print, [1, 2, 3])
That looks pretty nice when you already have a function lying around, like print. When you just have some arbitrary expression and you want to use it in map, you need to create a function out of it with a def or a lambda, like this:
new_values = map(lambda x: print(x), [1, 2, 3])
That's the ugliness you apparently want to avoid. And Python has a nice way to avoid it: comprehensions:
new_values = [print(x) for x in values]
However, in this case, you're just trying to execute some statement for each value, not accumulate the new values for each value. So, while this will work (you'll get back a list of None values), it's definitely not idiomatic.
In this case, the right thing to do is to write it explicitly—no closures, no functions, no comprehensions, just a loop:
for x in values:
print x
The most idiomatic:
for x in [1,2,3]:
print x
You can use numpy for vectorized arithmetic over an array:
>>> import numpy as np
>>> a = np.array([1, 2, 3])
>>> a * 3
array([3, 6, 9])
You can easily define a lambda that can be used over each element of an array:
>>> array_lambda=np.vectorize(lambda x: x * x)
>>> array_lambda([1, 2, 3])
array([1, 4, 9])
But as others have said, if you want to just print each, use a loop.
There are also libraries that wrap objects to expose all the usual functional programming stuff.
PyDash http://pydash.readthedocs.org/en/latest/
underscorepy (Google github underscore.py)
E.g. pydash allows you to do things like this:
>>> from pydash import py_
>>> from __future__ import print_function
>>> x = py_([1,2,3,4]).map(lambda x: x*2).each(print).value()
2
4
6
8
>>> x
[2, 4, 6, 8]
(Just always remember to "trigger" execution and/or to un-wrap the wrapped values with .value() at the end!)
without need of an assignment:
list(print(_) for _ in [1, 2, 3])
or just
[print(_) for _ in [1, 2, 3]]

Categories