web-dev-qa-db-ja.com

Haskellのリストで要素のインデックスを見つけますか?

リストから指数の最大値を見つける Haskell に関数があります。

prob99 = maximum $ map (\xs -> (head xs)^(head (tail xs))) numbers

私が見つける必要があるのは、結果のリストでこの最大値の場所です。これについてどうすればいいですか?

編集:私はこのような解決策を見つけました:

n = [[519432,525806],[632382,518061]....
prob99b [a,b] = b* (log a)
answer = snd $ maximum (Zip  (map prob99b n) [1..])
28
Jonno_FTW

最大要素のインデックスを見つける方法は?すべてのインデックスを試し、それらが最大であるかどうかを確認してみませんか?

ghci> let maxIndex xs = head $ filter ((== maximum xs) . (xs !!)) [0..]

しかし、これは関数がすでに存在するもののように聞こえます。既存の関数を使用すると、私のコードはより読みやすく、保守しやすくなり、おそらくさらに効率的になります。

参考までに、Haskellの型シグネチャで検索できる Hoogle と質問することもできます(Willが提案したとおり):

$ hoogle "Ord a => [a] -> Int" | head

<Nothing relevant>

$ # hmm, so no function to give me the index of maximum outright,
$ # but how about finding a specific element, and I give it the maximum?
$ hoogle "a -> [a] -> Int" | head
Data.List elemIndex :: Eq a => a -> [a] -> Maybe Int
Data.List elemIndices :: Eq a => a -> [a] -> [Int]
35
yairchu
import Data.List
elemIndex 'b' "abc" === Just 1

Haskell関数を見つけるための本当に良いツールは Hoogle です。特にタイプシグネチャで検索できます。

すべてを1つのパスで実行したい場合は、Data.List.mapAccumLをお勧めします。これまでに見つかった最大数のインデックスをアキュムレータとして渡します。

33
Will

これはおそらく彼自身の答えに値するに値しませんが、私はまだコメントできません。とにかく、これが私がこれを書いた方法です:

import Data.List
import Data.Ord

maxIndex ::  Ord a => [a] -> Int
maxIndex = fst . maximumBy (comparing snd) . Zip [0..]
7
Maxime Henrion

Haskellで数値計算をしている場合、それをより簡単かつ効率的にするライブラリを調べたいと思うかもしれません。たとえば hmatrix には、効率的なmaxIndexsのためのメソッドVectorがあり、そのドキュメントは次のとおりです。 https://hackage.haskell.org/package /hmatrix-0.17.0.1/docs/Numeric-LinearAlgebra-Data.html#g:14

> maxIndex $ vector [1, 3, 2]
1

質問が最初に尋ねられたとき、メソッドの正確な名前は異なりましたが、ライブラリもその頃にありました。

1
Daniel Landau

私はハスキーの初心者なので、次のように考えます。

  1. Haskellリストはリンクされたリストなので、要素にインデックスを手動でアタッチする必要があります:_Zip [0..] xs_。 (Haskellインデックスはゼロから始まることに注意してください。つまり、リストの先頭は_​​x !! 0_です。)
  2. 各タプルの2番目の要素に従って、この圧縮リスト[(0, x!!0), (1, x!!1), ..., (n, x!!n)]の最大値を見つけたいと思います。私がHaskellをよく知っていることに基づいて、いくつかの代替案があります:

    • これらの関数が存在することだけを知っていれば、maximumBy (comparing snd)を使用してMaxime 以下に記述 としてこれを書くことができます。
    • maximumByが存在することを知りませんでしたが、このようなものを疑っていたため、使用する型シグネチャに基づいて Hoogle で検索できました。 2つのaパラメータの比較関数を使用して、a要素のリストからジェネリック型aをタイプします(_a -> a -> Ordering_)–完全にどちらかです[a] -> (a -> a -> Ordering) -> a、またはより論理的な引数の順列。考えてみると、リストを最後から2番目の引数として指定する方が理にかなっています。これは、すぐにわかるように、より良いカレー化を可能にするためです 検索してみましょう _(a -> a -> Ordering) -> [a] -> a_。
    • 私は無知であるか、自分ですべてを書くことができる(または単にしたい)と思うので、次のように書くことができます。
    _import Data.List (foldl1')
    
    maxBySnd :: Ord a => [(Int, a)] -> (Int, a)
    maxBySnd = foldl1 cmpBySnd
      where
        cmpBySnd (i, xi) (j, xj) = case xi `compare` xj of
                                     LT -> (j, xj)
                                     _  -> (i, xi)
    _

    _foldl1'_は左からフォールディングを開始し(アキュムレータがフォールディング関数の左側にあることを意味します)、累積インデックスはxjxiより大きい場合にのみ更新されるため、これは最初の最大値のインデックスを返します。 _Data.List_をインポートすることに恨みがあり、1000項目の長いリストで機能しない場合は、Preludeの_foldl1_で問題ありません。 _Data.Vector_パッケージは同様のアプローチを使用し、「maxIndexhere および here を検索するだけです。

    • 比較可能なオブジェクトの型クラスOrdさえ知りません。その場合、cmpBySnd
    _    cmpBySnd (i, xi) (j, xj) = if xi < xj then j else i
    _

    この時点では、代数的データ型と高次関数の利点を見逃しているでしょう(知らない場合、これを実現するのはほとんど不可能です)。そのため、1)質問するのは良いことです。 2)次の読者に Learn You A Haskell For Great Good 、または Real World Haskell 、または this SO回答 、または このGitHubリポジトリ

  3. 結果の_(i, xi)_タプルの最初の要素を取得する必要があります。できれば組み込み関数fst :: (a, b) -> aまたは自家製の関数first (a,b) = aを使用します。

最終結果は次のとおりです。

_import Data.List (maximumBy)
import Data.Ord (comparing)

maxIndex :: Ord a => [a] -> Int
maxIndex = fst . maximumBy (comparing snd) . Zip [0..]
-- or
-- maxIndex = fst . maxBySnd . Zip [0..]
_
1
Laszlo Treszkai