Python: For each list element apply a function across the list

104,120

Solution 1

You can do this using list comprehensions and min() (Python 3.0 code):

>>> nums = [1,2,3,4,5]
>>> [(x,y) for x in nums for y in nums]
[(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (4, 1), (4, 2), (4, 3), (4, 4), (4, 5), (5, 1), (5, 2), (5, 3), (5, 4), (5, 5)]
>>> min(_, key=lambda pair: pair[0]/pair[1])
(1, 5)

Note that to run this on Python 2.5 you'll need to either make one of the arguments a float, or do from __future__ import division so that 1/5 correctly equals 0.2 instead of 0.

Solution 2

If I'm correct in thinking that you want to find the minimum value of a function for all possible pairs of 2 elements from a list...

l = [1,2,3,4,5]

def f(i,j):
   return i+j 

# Prints min value of f(i,j) along with i and j
print min( (f(i,j),i,j) for i in l for j in l)

Solution 3

Some readable python:

def JoeCalimar(l):
    masterList = []
    for i in l:
        for j in l:
            masterList.append(1.*i/j)
    pos = masterList.index(min(masterList))
    a = pos/len(masterList)
    b = pos%len(masterList)
    return (l[a],l[b])

Let me know if something is not clear.

Solution 4

If you don't mind importing the numpy package, it has a lot of convenient functionality built in. It's likely to be much more efficient to use their data structures than lists of lists, etc.

from __future__ import division

import numpy

data = numpy.asarray([1,2,3,4,5])
dists = data.reshape((1,5)) / data.reshape((5,1))

print dists

which = dists.argmin()
(r,c) = (which // 5, which % 5) # assumes C ordering

# pick whichever is most appropriate for you...
minval = dists[r,c]
minval = dists.min()
minval = dists.ravel()[which]

Solution 5

If working with Python ≥2.6 (including 3.x), you can:

from __future__ import division
import operator, itertools

def getmin(alist):
    return min(
        (operator.div(*pair), pair)
        for pair in itertools.product(alist, repeat=2)
    )[1]

getmin([1, 2, 3, 4, 5])

EDIT: Now that I think of it and if I remember my mathematics correctly, this should also give the answer assuming that all numbers are non-negative:

def getmin(alist):
    return min(alist), max(alist)
Share:
104,120

Related videos on Youtube

Ankur Ankan
Author by

Ankur Ankan

Updated on April 24, 2020

Comments

  • Ankur Ankan
    Ankur Ankan about 4 years

    Given [1,2,3,4,5], how can I do something like

    1/1, 1/2, 1/3,1/4,1/5, ...., 3/1,3/2,3/3,3/4,3/5,.... 5/1,5/2,5/3,5/4,5/5
    

    I would like to store all the results, find the minimum, and return the two numbers used to find the minimum. So in the case I've described above I would like to return (1,5).

    So basically I would like to do something like

    for each element i in the list map some function across all elements in the list, taking i and j as parameters store the result in a master list, find the minimum value in the master list, and return the arguments i, jused to calculate this minimum value.

    In my real problem I have a list objects/coordinates, and the function I am using takes two coordinates and calculates the euclidean distance. I'm trying to find minimum euclidean distance between any two points but I don't need a fancy algorithm.

  • David Hanak
    David Hanak over 15 years
    Note that the 'key' argument to min is only accepted since 2.5
  • Kiv
    Kiv over 15 years
    Lists named "l" freak me out a little bit. Good solution though :)
  • Sheep
    Sheep over 15 years
    Yeah, I always call my generic lists 'lst'.
  • Sheep
    Sheep over 15 years
    I would have used zip(nums, nums) instead of the listcomp, but otherwise that would have been my solution.
  • Andrea Ambu
    Andrea Ambu over 15 years
    I'd add a [1:] at the end: print min( (1.*i/j,i,j) for i in l for j in l)[1:]
  • Kiv
    Kiv over 15 years
    Actually, zip(nums, nums) results in [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)], which is not correct.
  • Kenan Banks
    Kenan Banks over 15 years
    Thought about it, but it felt much less readable to me @Andrea
  • Andrea Ambu
    Andrea Ambu over 15 years
    @Triptych: the 1.*i/j or the [1:] ?!?
  • Kenan Banks
    Kenan Banks over 15 years
    @Andreas, the [1:]. I abstracted out the division to make it clear that any function could be there.
  • Leonel
    Leonel about 15 years
    For a better use of memory, instead of a list, you can use a generator: nums = [1, 2, 3, 4, 5] pairs = ((x, y) for x in nums for y in nums) m = min(pairs, key=lambda pair: pair[0] / pair[1]) Thus, each pair is generated sequentially, which is more memory-efficient than keeping a list of pairs.
  • liori
    liori almost 15 years
    If the OP wants to calculate euclidean distance, there's itertools.combinations generator which will yield only unique pairs of different values from input.
  • Ishbir
    Ishbir almost 15 years
    @liori: the OP does not seem to want euclidean distances. Thanks for your comment, anyway, since it reminded me of the question.
  • ToolmakerSteve
    ToolmakerSteve over 10 years
    BTW, Does not do what the question asks. Yes, it is the solution to the simple example in the question, but it does not say how to apply some function to pairs of numbers. (Or perhaps the question was improved after this answer was posted.)
  • moooeeeep
    moooeeeep over 8 years
    For those wondering about the single underscore in the posted code: What is the purpose of the single underscore “_” variable in Python?