列出没有帐户的国民保险号码

时间:2012-11-11 22:24:13

标签: haskell

我正在尝试列出一堆不属于特定银行的数字。

这是我的代码

类型

     type NI = Int
     type Age = Int
     type Balance = Int
     type Person = (NI, Age, Balance)
     type Bank = [Person]
     type Market = [Bank]
     type Pop = [NI]

银行

     rbs :: Bank
     rbs = [ (1, 73, 1000)
         , (2, 18, -50)
         , (3, 60, 190)
         , (4, 26, 300)
         , (5, 24, 456)
         , (6, 32, 7500)
         , (7, 41, -46)
         , (8, 59, -850)
         , (9, 44, 348)
         , (10, 66, -1000)

     clyde :: Bank
     clyde = [(1, 73, 240)
           , (2, 18, -70)
           , (23, 30, 800)
           , (14, 16, 30)
           , (5, 24, 800)
           , (19, 81, 750)
           , (17, 49, 946)
           , (20, 59, -850)
           , (29, 24, -348)
           , (30, 76, -100)

    sco :: Pop
    sco = [1..20]

这是我的代码,用于检查NI是否不在银行

    bankFree :: Pop -> Market -> Pop
    bankFree [] x = []
    bankFree x [] = error "No Banks selected"
    bankFree x [[]] = []
    bankFree (x:xs) [[],((n,a,b):ys)] = if x == n then bankFree (xs) [[],ys]
                                else x : bankFree xs [[],ys]
    bankFree x [[],[]] = []
    bankFree (x:xs) (((n,a,b):ys):zs) = if x == n then bankFree (xs) ((ys):zs)
                                else if x /= n then x : bankFree xs ((ys):zs)
                                else bankFree (xs) zs

如果我运行bankFree sco [rbs,clyde]应该显示的是[11,12,13,15,16,18,20]然而出现的是[2..20]

我不知道我做错了什么以及如何继续,所以对此事的任何帮助都将不胜感激

3 个答案:

答案 0 :(得分:5)

同样,正如我在my answer to your earlier question中所建议的那样,你遇到这么多困难的原因是你没有把问题有效地分解成小块,而你却没有帮助自己标准实用程序用于管理列表。你试图一次咬掉一块太大的东西,这很难解决。

因此,您希望将问题分解为易于自行解决的子部分,然后将这些部分组合成解决大问题的重要解决方案:

import Data.List (any)

type Market = [Bank]
type Bank = [Person]
data Person = Person { ni :: NI, age :: Age, balance :: Balance } 
    deriving (Eq, Show)

bankFree :: Pop -> Market -> Pop
bankFree pop banks = filter checkBanks pop
    where checkBanks n = not (any (bankHasNI n banks))

bankHasNI :: NI -> Bank -> Bool
bankHasNI n bank = any (\person -> ni person == n) bank

必读:

答案 1 :(得分:2)

将其分解为更小的问题。此外,使用高阶函数而不是手动递归来使您的算法更容易理解:

inBank :: NI -> Bank -> Bool
ni `inBank` bank = any (\(ni', _, _) -> ni' == ni) bank

inMarket :: NI -> Market -> Bool
ni `inMarket` market = any (ni `inBank`) market

bankless :: Pop -> Market -> Pop
bankless pop market = filter (not . (`inMarket` market)) pop

如果你测试一下,你会得到:

>>> bankless sco [rbs, clyde]
[11,12,13,15,16,18]

答案 2 :(得分:2)

我想这是家庭作业,所以只是为你解决问题并不好,但这里有一些提示:

  • 这有助于将您的功能正式化为一个问题:“鉴于此人口并给出了这些银行客户列表,他们中谁没有帐户?”
  • 鉴于上述问题的表述,将bankFree函数视为过滤器是很自然的。以下是一些人,每个的人,只有在没有银行帐户的情况下才能保留。

过滤列表可以通过多种不同的方式实现,对初学者来说最简单的方法可能是使用列表理解:

bankFree :: Pop -> Market -> Pop
bankFree pop market = [p | p <- pop, not (isBankCustomer market p)]

应该被理解为:返回Pop中非银行客户的所有人员isBankCustomer的定义应为:

isBankCustomer :: NI -> Market -> Bool   
isBankCustomer ni market = ?   

你想在这里做的是以某种方式检查ni是否存在于任何银行客户名单中。