从列表创建列表列表,同时更改一个且始终不同的值Haskell

时间:2019-02-20 17:27:04

标签: list haskell int

我有9个整数的列表,其值分别为1,-1、0,例如:

[-1, 0, 0, 1, -1, -1, 1, 1, 0] 

我想做的是从这个列表创建一个列表列表,其中每个列表仅包含一个更改,并且始终不同。对于每个-1,我想将其更改为0。

示例:

从列表中:

[-1,0,0,1,-1,-1,1,1,0], 

我想得到结果:

[ [ 0, 0, 0, 1, -1, -1, 1, 1, 0]
, [-1, 0, 0, 1,  0, -1, 1, 1, 0]
, [-1, 0, 0, 1, -1,  0, 1, 1, 0]
]

因此,每个列表仅更改了一个值,并且每个列表都有不同的值。我什至不知道如何开始。

3 个答案:

答案 0 :(得分:1)

您始终需要做的第一件事就是弄清楚函数的类型签名。根据您的情况

lister :: [Int] -> [[Int]]

然后,当您要遍历列表但要跟踪已更改的索引时,一种简单的方法是列出列表的列表(很难理解,只看代码即可)然后压缩它及其索引。然后,对于每个列表,将元素切换到该位置。这是你的代码

lister :: [Int] -> [[Int]]
lister ls = [switch i l | (i,l) <- zip [0..9] (repeat ls)]

然后,您需要一个切换功能,以根据您的规则将元素切换到第i个位置:

switch :: Int -> [Int] -> [Int]
switch 0 ls = ls
switch n ls = [if i == n && x == -1 then 0 else x | (i,x) <- zip [1..] ls]

请注意,这将返回9个列表,原始列表中的每个元素一个。因此,它包含一些重复项。您可以使用nub中的Data.List消除它们,请注意,因为它是O(n^2)

这是您的完整代码:

import Data.List

lister :: [Int] -> [[Int]]
lister ls = nub [switch i l | (i,l) <- zip [0..9] (repeat ls)]

switch :: Int -> [Int] -> [Int]
switch 0 ls = ls
switch n ls = [if i == n && x == -1 then 0 else x | (i,x) <- zip [1..] ls]

答案 1 :(得分:1)

显然,这是一个非常具体的问题。从更大的角度看通常是有用的:这是什么特殊情况?显然,在这里,我们正在浏览一个列表,并且可能会看到我们希望以零种或多种方式替换的元素。此外,我们希望看到有几种方法可以进行有限数量的此类替换。因此,在考虑如何专门解决我们最初的问题之前,让我们先实施一般情况:

import Control.Applicative (Alternative, empty, (<|>))

replaceNTimes :: Alternative f => (a -> f a) -> Int -> [a] -> f [a]
replaceNTimes _ 0 xs = pure xs
replaceNTimes _ _ [] = empty
replaceNTimes f n (x:xs) = replaceHere <|> keepLooking
  where replaceHere = (:) <$> f x <*> replaceNTimes f (n - 1) xs
        keepLooking = (x:) <$> replaceNTimes f n xs

如果我们有一个零替换的“预算”,我们只返回列表的剩余部分。如果我们有剩余预算,但列表为空,则会中止,因为我们无法进行预期的更换次数。否则,我们将咨询我们的replacement-suggester函数,以查看在当前位置上哪些替换是合法的,然后选择创建其中一个替换并使用较小的N进行递归,或者选择不替换并使用相同的N进行递归。

使用此工具,最初的问题很容易:我们将N专门化为1(精确地进行一次替换),并提供了仅建议将0替换为-1的替换功能:

replaceSingleNegativeOneWithZero :: [Int] -> [[Int]]
replaceSingleNegativeOneWithZero = replaceNTimes go 1
  where go (-1) = [0]
        go _ = []

并进行测试以确保我们获得了预期的输出:

*Main> replaceSingleNegativeOneWithZero [-1,0,0,1,-1,-1,1,1,0]
[ [0,0,0,1,-1,-1,1,1,0]
, [-1,0,0,1,0,-1,1,1,0]
, [-1,0,0,1,-1,0,1,1,0]]

答案 2 :(得分:0)

另一种尝试:

library(RSQLite)
library(dplyr)

#create dummy SQL database
set.seed(123)
tax<-tibble(taxpayer_id=1:10,income=runif(10,50,60),income_misc=runif(10,0,5)) %>% 
  mutate(income_misc=ifelse(income_misc<2,NA,income_misc))
con <- dbConnect(RSQLite::SQLite(), ":memory:")
dbWriteTable(con,"tax_tbl",tax,overwrite=TRUE)


# now extract
tax_db <- tbl(con, 'tax_tbl')
tax_db
#> # Source:   table<tax_tbl> [?? x 3]
#> # Database: sqlite 3.22.0 [:memory:]
#>    taxpayer_id income income_misc
#>          <int>  <dbl>       <dbl>
#>  1           1   52.9        4.78
#>  2           2   57.9        2.27
#>  3           3   54.1        3.39
#>  4           4   58.8        2.86
#>  5           5   59.4       NA   
#>  6           6   50.5        4.50
#>  7           7   55.3       NA   
#>  8           8   58.9       NA   
#>  9           9   55.5       NA   
#> 10          10   54.6        4.77

tax <- tax_db %>% 
  as_tibble() %>% #have to create a data frame, not database, to modify NAs
  mutate_all(funs(replace(., is.na(.), 0)))

dbDisconnect(con)

tax
#> # A tibble: 10 x 3
#>    taxpayer_id income income_misc
#>          <dbl>  <dbl>       <dbl>
#>  1           1   52.9        4.78
#>  2           2   57.9        2.27
#>  3           3   54.1        3.39
#>  4           4   58.8        2.86
#>  5           5   59.4        0   
#>  6           6   50.5        4.50
#>  7           7   55.3        0   
#>  8           8   58.9        0   
#>  9           9   55.5        0   
#> 10          10   54.6        4.77
Created on 2019-02-20 by the reprex package (v0.2.1)

用法:

zeros :: [Int] -> [Int] -> [[Int]]
zeros _ []     = []
zeros h (x:xs) = [h ++ newX:xs] ++ zeros nextH xs
    where newX = if x == (-1) then 0 else x
        nextH = h ++ [x]

switch xs = ((filter (/= xs)) . (zeros [])) xs