リストをフィルタリングして、整数のリストのみを返すにはどうすればよいですか?
たとえば、次のようにリストをフィルタリングすると、[1, 1.2, 2, 2.2]
が返され[1, 2]
ます。
[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
nonFractional
asの定義を変更する場合は、@David のアイデアを使用します。
nonFractional d = (fromIntegral $ ceiling d :: Rational) == d
次に、大きな分数でも機能するようです
> nonFractional (12345678987654321.5)
True
まず第一に、あなたのリストは均質でなければならないので、 と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
役立つでしょう。
には多くの解決策が投稿されていRational
ますが、実際には分母を 1 と比較するだけで済みます。
hasFraction' :: Rational -> Bool
hasFraction' = (/= 1) . denominator
これは任意に一般化できReal
、数値に小数部があるかどうかを確認する最も安全な方法の 1 つです。
hasFraction :: (Real a) => a -> Bool
hasFraction = hasFraction' . toRational
その関数は丸め誤差の問題を解決しませんが、それは当然のことです。丸め誤差が気になる場合は、間違ったデータ型を使用しています。
これはどうですか:
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]
どこからデータを取得したかによって異なります。
Haskell では、純粋な整数と非整数を混在させることはできません。そのため、 のようDouble
なより正確なものを使用しない限り、整数はデータ型に固有の不正確さで汚染されRational
ますが、とにかく非整数が必要ない場合は、可能であれば、数値データになる前にソースで破棄してください。
getInt
ます。getInt
てください。getInt
String を 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が取り除かれ、Nothing
s がアンラップされますJust
。それを取得するには、一番上にいる必要があります
import Data.Maybe (catMaybes)
。
データがある種の浮動小数点数である場合、浮動小数点型に真の等価性はないことに注意してください。そのため、チェックする前により正確な表現に変換したとしても、元の数値が正しいかどうかを知ることは論理的に不可能です。データは、正確な整数、またはデータが取得される前に浮動小数点表現が丸められた整数に非常に近いものを表していました。例えば:
Prelude> (12345678987654321.6 :: Double) == 12345678987654322.0
True
一方
Prelude> (12345678987654321.6 :: Rational) == 12345678987654322.0
False
ただし、データ型を選択できる場合は、生成コードを制御できるため、非整数を含めないことを選択してください!
要約: 非整数を数値データに変換する前に取り除くのが最も簡単で、時折奇妙な丸め誤差が発生することはありません。
リストは、タイプ[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]