2012-01-23 4 views
3

たとえば、list = [1,2,3,4]listProduct list[1,2,3,4,6,8,9,12,16]を返します。つまり[(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が含まれていないのはなぜですか?

あなたは重複をしたいです場合ならば、それは---、その後、--- ---つまり、あなたが重複を望んでいない一方

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

1*4と同じだからそれはだ場合

:あなたが最初のソリューションのより効率的なバージョンで triangularAutoZipWithを使用することができ、その後

listProduct' xs = triangularAutoZipWith (*) 

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

---リスト内の後続の各数で各番号を乗算したい、との結果で重複を含めますあなたがしている場合は、重複して

listProduct = nub . triangularAutoZipWith (*) 
+0

ありがとうございます。私はナブの使用を避けたいと思っていました。それは、ナブがいくつかの重大なパフォーマンスへの影響を与えているようです。これは動作しますが。 – ryanmehta

9

あなたはリストの内包表記を使用して簡単な方法でこれを書くことができます。

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

しかし、それはリストモナドを使用することがより慣用的です:(listProduct xs = liftM2 (*) xs xsに相当)

import Control.Monad 

listProduct = join $ liftM2 (*) 

このバージョンを理解するには、liftM2を一般的な種類のCartesian productと考えることができます(liftM2 (,)はデカルト積自体)。それはあなたがリストモナドにliftM2の定義を専門とする場合は、この動作を確認する方が簡単です:

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 (*)も同様に動作しますが、リストのApplicativeインスタンスは次のように定義されています。 Monadインスタンス。 )

4

使用して...

import Control.Applicative 

... ...

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

...とせず...

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

ルビー・ゴールドバーグ・ムード、あなたは...

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は、listyの要素です。listの要素です。あなたがx == yの製品を使用しない場合にも、例えば、いくつかの組み合わせをフィルタリングするために、リストの内包表記に条件を追加することができます。

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

より複雑な答えがリストの内包表記と等価であるという事実に関係していますリストMonad;リストタイプの標準タイプMonadの実装。

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

do -notationは、このためだけの構文糖である:

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

Landeiの答えはあなたがいないのであればという事実に基づいているこれはexample1またこれらの方法で実装することができることを意味しあなたのリストの理解の任意の条件を使用して、デカルト製品だけでより弱いApplicativeタイプのクラスを使用して離れて得ることができます。

関連する問題