[英]Haskell: Filter List with those that are Integers
我將如何過濾列表,以便僅返回整數列表?
例如,過濾類似[1, 1.2, 2, 2.2]
將返回[1, 2]
。
考慮到列表的類型為[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
的定義更改為nonFractional
,則使用nonFractional
的想法
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
進行一些包裝會有所幫助。
那這個呢:
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]
已經發布了許多針對Rational
的解決方案,實際上,您實際上只需要將分母與1進行比較:
hasFraction' :: Rational -> Bool
hasFraction' = (/= 1) . denominator
可以將其推廣到任何Real
並且是檢查數字是否有小數部分的最安全方法之一:
hasFraction :: (Real a) => a -> Bool
hasFraction = hasFraction' . toRational
該函數不能解決舍入誤差問題,但這很自然。 當四舍五入的錯誤困擾您時,您使用的是錯誤的數據類型。
這取決於您從何處獲取數據。
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]
,它擺脫了Nothing
並解開了Just
。 我們需要
在頂部import Data.Maybe (catMaybes)
以獲取它。
如果您的數據是某種浮點數,請記住,浮點類型沒有真正的相等性,因此,即使在檢查之前轉換為更准確的表示形式,從邏輯上講,您也不可能知道原始的數據表示一個精確的整數,或者非常接近浮點表示在數據到達之前四舍五入的整數。 例如:
Prelude> (12345678987654321.6 :: Double) == 12345678987654322.0
True
而
Prelude> (12345678987654321.6 :: Rational) == 12345678987654322.0
False
但是,如果可以選擇數據類型,則可以控制生成代碼,因此請選擇不包括非整數!
簡介:在將非整數轉換為數值數據之前 ,最簡單的方法是將其消除,並且不會遇到偶發的四舍五入錯誤。
您的列表必須是[Double]
或[Integer]
類型,或其他一些數字。 您不能混合類型。
就是說,如果您有一個雙精度數列表,並且試圖過濾掉不是整數的雙精度數,則始終可以使用round
, floor
或ceiling
來檢查該數字是否相等。
例如:
isInt :: (RealFrac a) => a -> Bool
isInt x = x == (fromIntegral $ round x)
然后,您可以使用filter
來filter
:
filter isInt [1, 1.2, 2, 2.2] -- [1.0, 2.0]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.