2012-01-23 10 views
3

Например, list = [1,2,3,4]. listProduct list возвращает [1,2,3,4,6,8,9,12,16] i.e [(1*1),(1*2),(1*3),(1*4),(2*3),(2*4),(3*3),(3*4),(4*4)]Как я могу умножить элементы списка на все остальные элементы?

Я помню, что было что-то, что делало это, но я больше не могу найти этот ресурс.

+2

Почему ваш пример не включает '2 * 2' в результат? Возможно, вам не нужны дубликаты. Но тогда почему ваш пример не включает '3 * 3' в результат? – dave4420

+0

Это была опечатка, спасибо! Сейчас обновлено – ryanmehta

ответ

5

Почему ваш пример не включает в себя 2*2?

Если это потому, что это то же самое, как 1*4 --- то есть, вы не хотите дубликаты --- то

listProduct xs = nub [x * y | x <- xs, y <- xs] 

С другой стороны, если вы хотите дубликаты --- если вы хотите умножить каждое число на каждом последующем номером в списке, и включают в себя дубликаты в результате --- затем

listProduct' xs = triangularAutoZipWith (*) 

triangularAutoZipWith op = concatMap f . tails 
    where f [] = [] 
     f xs @ (x : _) = map (op x) xs 

Вы можете использовать triangularAutoZipWith в более эффективной версии первого решения:

listProduct = nub . triangularAutoZipWith (*) 
+0

Спасибо. Я вроде хотел избежать использования нуба. Кажется, что nub имеет некоторые серьезные последствия для производительности. Хотя это и работает. – ryanmehta

9

Вы можете написать это в простой манере, используя список понимание:

listProduct xs = [x * y | x <- xs, y <- xs] 

Однако, это более идиоматических использовать список монады:

import Control.Monad 

listProduct = join $ liftM2 (*) 

(эквивалентный listProduct xs = liftM2 (*) xs xs)

Чтобы понять эту версию, вы можете думать о liftM2 как своего рода обобщенном Cartesian product (liftM2 (,) является Ca сам продукт rtesian). Это легче увидеть, как это работает, если вы специализируетесь liftM2 «s определение к списку монады:

liftM2 f mx my = do { x <- mx; y <- my; return (f x y) } 
-- expand the do notation 
liftM2 f mx my = mx >>= (\x -> my >>= (\y -> return (f x y))) 
-- substitute the list monad's definition of (>>=) 
liftM2 f mx my = concatMap (\x -> concatMap (\y -> [f x y]) my) mx 
-- simplify 
liftM2 f mx my = concatMap (\x -> map (\y -> f x y) my) mx 
-- simplify again 
liftM2 f mx my = concatMap (\x -> map (f x) my) mx 

Так монадическая определение listProduct расширяется до:

listProduct xs = concatMap (\x -> map (x *) xs) xs 

(Обратите внимание, что вы не технически нужна полная монада списка, все, что требуется, - это экземпляр Applicative для списков, и listProduct = join $ liftA2 (*) будет работать так же хорошо. Однако проще показать, как он работает с монадическим определением, поскольку экземпляр для списков определяется в терминах Monad tance.)

4

, используя ...

import Control.Applicative 

... с дубликатами ...

listProduct list = (*) <$> list <*> list 

... и без ...

listProduct list = concat (mul <$> list <*> list) where 
    mul a b | a <= b = [a*b] 
      | otherwise = [] 

Если вы находитесь в rube-goldberg-mood, вы можете использовать ...

listProduct list = concat $ zipWith (map.(*)) list (map ((`filter` list).(<=)) list) 

... или просто ...

import Data.List 

listProduct list = concat $ zipWith (map.(*)) list $ tails list 

[Редактировать]

Другой способ будет использовать sequence. С дублями:

listProduct = map product . sequence . replicate 2 

Без:

listProduct = map product . filter(\[a,b] -> a <= b) . sequence . replicate 2 
1

Ну, вы уже получили несколько ответов, но я собираюсь бросить в шахте, потому что я думаю, что более ранние, в то время как все точные, может оказаться недостаточно полезным.

Самое простое решение вы получили для новичка, чтобы понять список понимание:

example1 = [ x*y | x <- list, y <- list ] 

Этот синтаксис существует в некоторых популярных языков, таких как Python, и должно быть легко понять, в любом случае: « список, элементами которого являются результаты x*y, где x является элементом list и y является элементом list. " Вы можете также добавить условия в списковые, чтобы отфильтровать некоторые комбинации, например, если вы не хотите продуктов, где x == y:

example2 = [ x*y | x <- list, y <- list, x /= y ] 

Более сложные ответы должны делать с тем, что списочные эквивалентнами Список Monad; реализация стандартного класса Monad для типа списка. Это означает, что example1 также может быть реализован следующими способами:

example1' = do x <- list 
       y <- list 
       return (x*y) 

do -notation только синтаксисом для этого:

example1'' = list >>= (\x -> list >>= (\y -> return (x*y))) 

ответ Landei основывается на том факте, что, если вы не используя любые условия в вашем понимании списка, только декартовские продукты, вы можете уйти с использованием класса класса Applicative, который слабее, чем Monad.

Смежные вопросы