如何删除嵌套列表列表中的元素?

时间:2019-02-20 01:39:40

标签: r list nested

我怎么走

x <- list(p1 = list(type='A',score=list(c1=10,c2=8,c3=data.frame(a=1, b=3, c=5))),
       p2 = list(type='B',score=list(c1=9,c2=9,c3=data.frame(a=2, b=2))),
       p3 = list(type='B',score=list(c1=9,c2=7,c3=data.frame(a=2, b=2))))

到没有作为数据帧的“ c3”元素的列表?

最好以一种tidyverse友好的方式,或者我可以在管道中间放置的东西。

我已经尝试过list.remove,嵌套的lapply,rapply,Filter,但似乎无法使它们正常工作...而且我不想取消列出嵌套的列表结构。

(编辑:对不起,我在原始问题中的示例数据中有错字(请参见下文),但是如果您的解决方案在两种情况下均有效,那就太好了!)

x <- list(p1 = list(type='A',score=list(c1=10,c2=8,c3=data.frame(a=1, b=3, c=5))),
       p2 = list(type='B',score=list(c1=9,c2=9,c3=data.frame(a=2, b=2)),
       p3 = list(type='B',score=list(c1=9,c2=7,c3=data.frame(a=2, b=2)))))

3 个答案:

答案 0 :(得分:2)

这是使用modify_depth的正确方案,它是modify链访问深层嵌套列表的快捷方式。 modify在这个问题上比map有一个优势,因为它可以保留输入的类型,而不是将所有内容强制转换为列表,如果您具有列表结构的矢量元素,这可能是相关的。

使用给定的输入(内部包含p3元素,而不是与p2处于同一级别),第二级和第三级的数据帧元素将按以下方式discard进行分类。为了搜索嵌套列表的所有级别,我们可以设置一个while循环来遍历这些级别,并在处理过程中丢弃数据帧。我们需要.ragged = TRUE来处理列表深度的错误。此版本从下至上搜索,但您也可以将其更改为从上至下搜索。

library(tidyverse)
x <- list(
  p1 = list(type = "A", score = list(c1 = 10, c2 = 8, c3 = data.frame(a = 1, b = 3, c = 5))),
  p2 = list(
    type = "B", score = list(c1 = 9, c2 = 9, c3 = data.frame(a = 2, b = 2)),
    p3 = list(type = "B", score = list(c1 = 9, c2 = 7, c3 = data.frame(a = 2, b = 2)))
  )
)

remove_dataframes <- function(input_list) {
  current_list <- input_list
  current_depth <- vec_depth(current_list)
  # current_depth <- max_depth
  while (current_depth > 1) {
    current_list <- modify_depth(
      .x = current_list,
      .depth = current_depth,
      .f = ~ discard(., is.data.frame),
      .ragged = TRUE
    )
  current_depth <- current_depth - 1
  }
  return(current_list)
}

x %>%
  remove_dataframes %>%
  glimpse
#> List of 2
#>  $ p1:List of 2
#>   ..$ type : chr "A"
#>   ..$ score:List of 2
#>   .. ..$ c1: num 10
#>   .. ..$ c2: num 8
#>  $ p2:List of 3
#>   ..$ type : chr "B"
#>   ..$ score:List of 2
#>   .. ..$ c1: num 9
#>   .. ..$ c2: num 9
#>   ..$ p3   :List of 2
#>   .. ..$ type : chr "B"
#>   .. ..$ score:List of 2

reprex package(v0.2.1)于2019-02-20创建

答案 1 :(得分:2)

您可以编写自己的函数来做到这一点:

class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public override void Configure(Container container)
{
    SetConfig(new HostConfig {
        DefaultRedirectPath = "/metadata",
        DebugMode = AppSettings.Get(nameof(HostConfig.DebugMode), false)
    });

    container.Register<IDbConnectionFactory>(c => new OrmLiteConnectionFactory(
        "Server=localhost;Database=test;UID=root;Password=test;SslMode=none",
        MySqlDialect.Provider));

    using (var db = container.Resolve<IDbConnectionFactory>().OpenDbConnection())
    {
        db.DropAndCreateTable<Person>();

        db.Insert(new Person {Id = 1, Name = "Name"});

        var s = db.Select<Person>().Dump();
        s.PrintDump();
    }

    var model = ModelDefinition<Person>.Definition;
    model.Name.Print();
}

这也很受欢迎,因为它可以丢弃您需要的所有东西。例如,尝试check = function(x,name){ m = names(x)%in% name x = if(any(m)) x[!m] else x if(is.list(x)) sapply(x,check,name) else x } dput(check(x,'c3')) list(p1 = list(type = "A", score = list(c1 = 10, c2 = 8)), p2 = list( type = "B", score = list(c1 = 9, c2 = 9), p3 = list(type = "B", score = list(c1 = 9, c2 = 7))))

答案 2 :(得分:2)

这是在 rrapply() 包中使用 rrapply 的另一种替代方法,适用于任意级别的嵌套:

library(rrapply)

x1 <- rrapply(x, condition = function(x, .xparents) !any(.xparents == "c3"), how = "prune")
str(x1)  
#> List of 3
#>  $ p1:List of 2
#>   ..$ type : chr "A"
#>   ..$ score:List of 2
#>   .. ..$ c1: num 10
#>   .. ..$ c2: num 8
#>  $ p2:List of 2
#>   ..$ type : chr "B"
#>   ..$ score:List of 2
#>   .. ..$ c1: num 9
#>   .. ..$ c2: num 9
#>  $ p3:List of 2
#>   ..$ type : chr "B"
#>   ..$ score:List of 2
#>   .. ..$ c1: num 9
#>   .. ..$ c2: num 7