0

リストをフィルタリングして、整数のリストのみを返すにはどうすればよいですか?

たとえば、次のようにリストをフィルタリングすると、[1, 1.2, 2, 2.2]が返され[1, 2]ます。

4

6 に答える 6

6

[Double]さまざまなタイプの要素を含むリストを(簡単な方法で)持つことができないため、リストがタイプであると考えてください。

double のリストを取得したら、関数 を使用できますceiling

ceiling 2.1 = 3
ceiling 2.0 = 2

したがって、数値に小数部分がないかどうかを確認する関数は、次のように記述できます。

nonFractional d = (fromIntegral $ ceiling d) == d

これでフィルターをかけることができます

> filter nonFractional [1, 1.2, 2, 2.2]
[1.0,2.0]

(編集) 等値を比較する上記のアプローチは、次のような大きな数では機能しません。

> nonFractional  (12345678987654321.5)
True

nonFractionalasの定義を変更する場合は、@David のアイデアを使用します。

nonFractional d = (fromIntegral $ ceiling d :: Rational) == d

次に、大きな分数でも機能するようです

> nonFractional  (12345678987654321.5)
True
于 2012-09-25T06:47:27.813 に答える
5

まず第一に、あなたのリストは均質でなければならないので、 とIntegerのリストを持つことはできませんDoubles

properFraction数値を整数部分と小数部分に分解する便利な関数 があります。

properFraction :: (Fractional a, Integral b) => a -> (b,a)

したがって、数値にゼロ以外の小数部があるかどうかを判断する関数を定義できます。

> let haveNoFractionalPart = (== 0.0) . snd . properFraction 
haveNoFractionalPart :: Double -> Bool

いいえ、その関数でリストをフィルタリングできます:

> filter haveNoFractionalPart [1, 1.2, 2, 2.2]
[1.0,2.0]

更新

私の解決策は、現実世界のいくつかのケースでは有効ではなく、実行可能ではないことを認めなければなりません。のようなもののために

> properFraction (11111111111111111111.1)
(11111111111111110656,0.0)

Integerとにかく、持っている値のリストから呼び出すものをフィルタリングする必要がある場合を想像するのは難しいです。また、浮動小数点を持つ任意の数値が 100% の確率でゼロの浮動小数点を持つことを定義する方法はありません。

たぶん、いくつかのラッパーがIntegerあり、Double役立つでしょう。

于 2012-09-25T06:29:28.633 に答える
1

には多くの解決策が投稿されていRationalますが、実際には分母を 1 と比較するだけで済みます。

hasFraction' :: Rational -> Bool
hasFraction' = (/= 1) . denominator

これは任意に一般化できReal、数値に小数部があるかどうかを確認する最も安全な方法の 1 つです。

hasFraction :: (Real a) => a -> Bool
hasFraction = hasFraction' . toRational

その関数は丸め誤差の問題を解決しませんが、それは当然のことです。丸め誤差が気になる場合は、間違ったデータ型を使用しています。

于 2012-09-25T12:10:44.133 に答える
1

これはどうですか:

filterInt :: (RealFrac a) => [a] -> [Integer]
filterInt [] = []
filterInt (x:xs)
    | frac == 0 = a : filterInt xs
    | otherwise = filterInt xs
  where
      (a, frac) = properFraction x

テスト:

> let li = [1, 1.2, 2, 2.2]
> filterInt li
> [1,2]
于 2012-09-25T11:11:50.373 に答える
1

どこからデータを取得したかによって異なります。

Haskell では、純粋な整数と非整数を混在させることはできません。そのため、 のようDoubleなより正確なものを使用しない限り、整数はデータ型に固有の不正確さで汚染されRationalますが、とにかく非整数が必要ない場合は、可能であれば、数値データになる前にソースで破棄してください。

  • ユーザーからデータを取得した場合は、一連の数字のみを入力できる入力フォームを使用するか、以下を使用しgetIntます。
  • データベースまたはその他のテキストベースのソースからデータを取得した場合は、以下を使用しgetIntてください。
  • 制御していないコード (ライブラリまたは外部呼び出し) からデータを取得した場合、整数だけを取得する代替手段はありますか?
    そうであれば、それを使用し、そうでない場合は、他の回答で他の丸めベースのソリューションのいずれかを使用してください。

getIntString を Integer に変換し、Integer でないものは巧妙に無視します。

import Data.Char (isDigit)

getInt :: String -> Maybe Integer
getInt xs | all isDigit xs = Just (read xs)
          | otherwise      = Nothing

そうgetInt "12345"であるのJust 12345に対してgetInt 12345678987654321.1ですNothing。これを使用して、リストから整数以外の入力を削除できます。

getInts :: [String] -> [Integer]
getInts xss = catMaybes $ map getInt xss

もっと簡潔に言えば、 と書くことができます
getInts = catMaybes.map getInt

catMaybes :: [Maybe a] -> [a]これで、sが取り除かれ、Nothings がアンラップされますJust。それを取得するには、一番上にいる必要があります
import Data.Maybe (catMaybes)

データがある種の浮動小数点数である場合、浮動小数点型に真の等価性はないことに注意してください。そのため、チェックする前により正確な表現に変換したとしても、元の数値が正しいかどうかを知ることは論理的に不可能です。データは、正確な整数、またはデータが取得される前に浮動小数点表現が丸められた整数に非常に近いものを表していました。例えば:

Prelude> (12345678987654321.6 :: Double) == 12345678987654322.0
True

一方

Prelude> (12345678987654321.6 :: Rational) == 12345678987654322.0
False

ただし、データ型を選択できる場合は、生成コードを制御できるため、非整数を含めないことを選択してください!

要約: 非整数を数値データに変換する前に取り除くのが最も簡単で、時折奇妙な丸め誤差が発生することはありません。

于 2012-09-25T20:17:19.110 に答える
0

リストは、タイプ[Double]または[Integer]、、またはその他のタイプの番号である必要があります。タイプを混在させることはできません。

とはいえ、doubleのリストがあり、整数ではないものを除外しようとしている場合は、いつでも、、を使用roundして、数値との同等性を確認floorできます。ceiling

例えば:

isInt :: (RealFrac a) => a -> Bool
isInt x = x == (fromIntegral $ round x)

次に、これを使用してデータをフィルタリングできますfilter

filter isInt [1, 1.2, 2, 2.2] -- [1.0, 2.0]
于 2012-09-26T15:53:12.307 に答える