过滤列表类型data.table列中的数组

时间:2017-10-28 17:50:16

标签: arrays r list filter data.table

我正在尝试解决一个问题,即我刚刚找到的新路线(卡车),我检查该路线是否已经是我之前路线的一部分。例如,假设我存储的路由在数据表routelist中,node_list表示存储的路由。我想检查路由(5,6,7,8)所属的行。

library(data.table)
routelist=data.table(id=c(1:3),node_list=list(c(1:6),c(4:7),c(1:10)))
item<-c(5:8)
routelist[sum(item%in%unlist(packlist$node_list))==length(item)]

对于上面的检查,返回所有三行,但只返回第三行。我可以通过以下for循环来做到这一点,但它并不快,并没有考虑到顺序(并且应该有一种方法以更好的方式做到这一点)。 item中节点的顺序很重要,列表不需要是连续的,即项可以是c(5,7,8),并且应该在第3行返回,而c(5,8,7)不应该返回。

for(i in 1:3)
{
  if(sum(item%in%unlist(packlist[i]$node_list))==length(item))
    print(routelist[i])
}

3 个答案:

答案 0 :(得分:2)

这里有OP data.table方法存在两个问题。

缺少by子句

routelist = data.table(id = 1:3, node_list = list(1:6, 4:7, 1:10))
item <- 5:8
routelist[, sum(item %in% unlist(node_list)) == length(item)] 

返回单个TRUE值,因为

routelist[, unlist(node_list)]

返回单个向量

 [1]  1  2  3  4  5  6  4  5  6  7  1  2  3  4  5  6  7  8  9 10

如果按id分组,我们会得到所需的结果:

routelist[, sum(item %in% unlist(node_list)) == length(item), by = id]
   id    V1
1:  1 FALSE
2:  2 FALSE
3:  3  TRUE

routelist[routelist[, sum(item %in% unlist(node_list)) == length(item), by = id]$V1]
   id    node_list
1:  3 1,2,3,4,5,6,

%in%仅检查外观,但不检查订单

表达式sum(item %in% unlist(node_list)) == length(item)并不处理item中元素的顺序。

由于元素的顺序很重要,表达式

isTRUE(all(diff(match(item, unlist(node_list))) > 0))

说明订单。 match()返回itemnode_list元素的位置(如果未找到,则返回NA)。如果item中的订单与node_list中的订单相同,那么所有位置差异都必须为正数。需要isTRUE()来涵盖NA案例。

因此,

item <- c(5, 7, 8)
routelist[routelist[, isTRUE(all(diff(match(item, unlist(node_list))) > 0)), by = id]$V1]

返回

   id    node_list
1:  3 1,2,3,4,5,6,

尽管存在差距

item <- c(5, 8, 7)
routelist[routelist[, isTRUE(all(diff(match(item, unlist(node_list))) > 0)), by = id]$V1]

返回

Empty data.table (0 rows) of 2 cols: id,node_list
由于订单错误,

按要求。

答案 1 :(得分:1)

来自dplyrtidyr的解决方案。

如果订单不重要,可以使用以下方法。通过检查id中的routelist2列,很明显,ID 3是具有正确条件的列。

# Create example dataset
library(data.table)
routelist=data.table(id=c(1:3),node_list=list(c(1:6),c(4:7),c(1:10)))
item<-c(5:8)

# Solution 1
library(dplyr)
library(tidyr)

routelist2 <- routelist %>%
  unnest() %>%
  group_by(id) %>%
  filter(all(item %in% node_list)) %>%
  nest()

routelist2 
# A tibble: 1 x 2
     id              data
  <int>            <list>
1     3 <tibble [10 x 1]>

如果订单很重要,我们可能必须将路线编号转换为字符串,而不是找到正确的字符串模式。以下方法应该有效。

# Solution 2
item_str <- toString(item)

routelist3 <- routelist %>%
  rowwise() %>%
  mutate(node_list = toString(node_list)) %>%
  filter(grepl(item_str, node_list)) %>%
  ungroup()

routelist3
# A tibble: 1 x 2
     id                     node_list
  <int>                         <chr>
1     3 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

更新

以下考虑item2中的节点未完成的情况。

# Solution 3
library(dplyr)
library(tidyr)

item2 <- c(5, 7, 8)

routelist4 <- routelist %>%
  unnest() %>%
  group_by(id) %>%
  filter(all(item2 %in% node_list)) %>%
  filter(node_list %in% item2) %>%
  summarise(node_list = toString(node_list)) %>%
  filter(node_list == toString(item2))
routelist4
# A tibble: 1 x 2
     id node_list
  <int>     <chr>
1     3   5, 7, 8

答案 2 :(得分:0)

使用循环(不优雅)可以在正文中使用以下检查。它确实考虑到了顺序:

library(data.table)
routelist=data.table(id=c(1:3),node_list=list(c(1:6),c(4:7),c(1:10)))
item<-c(5,8,7)

for(i in 1:nrow(routelist))
{
  if(identical(intersect(unlist(routelist[i]$node_list),item),item)){
    print(routelist[i])  
  }

}