Как проверить на равенство списка независимо от порядка? - PullRequest
0 голосов
/ 10 июля 2019

Я использую testthat framework, но этот вопрос должен уместиться на более широком фоне. По сути, у меня есть функция, которая выводит это

list("PL+", "PW-", "PL+", "PW-", c("PL+", "PW-"))

Тем не менее, я не забочусь о заказе, так что это также совершенно нормально

list("PL+", c("PW-", "PL+"), "PL+", "PW-", "PW-")

Как проверить на равенство с expect_equal? Я думал о unlist, за которым следует sort, но это нарушит вложенную структуру.

Ответы [ 3 ]

1 голос
/ 10 июля 2019

Вы можете использовать purrr::map_depth для сортировки вложенных списков, а затем проверить списки с помощью setdiff. Если длина при вызове setdiff равна 0, списки содержат одинаковые элементы. Хитрость в том, что setdiff будет давать разные результаты в зависимости от порядка его аргументов, так что в итоге вы вызываете его дважды, по одному с каждого направления. Это похоже на двойную проверку, выполненную в testthat::expect_setequal.

Для простоты я оборачиваю это в функцию. Вместо этого вы могли бы сделать то же самое с комбинацией all и %in%, но это казалось компактным.

a1 <- list("PL+", "PW-", "PL+", "PW-", c("PL+", "PW-"))
b1 <- list("PL+", c("PW-", "PL+"), "PL+", "PW-", "PW-")

nested_equal <- function(l1, l2) {
  left_diff <- setdiff(
    purrr::map_depth(l1, 1, sort),
    purrr::map_depth(l2, 1, sort)
  )
  right_diff <- setdiff(
    purrr::map_depth(l2, 1, sort),
    purrr::map_depth(l1, 1, sort)
  )
  (length(left_diff) == 0) & (length(right_diff) == 0)
}

nested_equal(a1, b1)
#> [1] TRUE

Несколько тестовых случаев с разными элементами:

a2 <- list("PL+", "PW-", "PL+", "PW-", c("PL+", "PW-"), "A")
b2 <- list("PL+", c("PW-", "PL+"), "PL+", "PW-", "PW-")

nested_equal(a2, b2)
#> [1] FALSE

a3 <- list("PL+", "PW-", "PL+", "PW-", c("PL+", "PW-"))
b3 <- list("PL+", c("PW-", "PL+", "X"), "PL+", "PW-", "PW-", "B")

nested_equal(a3, b3)
#> [1] FALSE

Чтобы соответствовать тестам testthat, вы можете проверить значение true или false, возвращаемое nested_equal в expect_equal, expect_true, expect_false.

0 голосов
/ 10 июля 2019

Прокручивать элементы списков и сверяться друг с другом

l1 = list("PL+", "PW-", "PL+", "PW-", c("PL+", "PW-"))
l2 = list("PL+", c("PW-", "PL+"), "PL+", "PW-", "PW-")
temp = sapply(l1, function(x) sapply(l2, function(y) identical(sort(x), sort(y))))
all(rowSums(temp) > 0) & all(colSums(temp) > 0)
#[1] TRUE
0 голосов
/ 10 июля 2019

sort() и unlist(), вероятно, будут лучшей ставкой.

identical(sort(unlist(a1)), sort(unlist(b1)))

Вы выражали сомнение по поводу нарушения вложенной структуры, но обратите внимание, что sort(unlist(...)) не является постоянным.Вы по-прежнему можете получить доступ к любому списку без проблем.

Кроме того, хотя я незнаком с пакетом testthat, expect_equal или expect_identical должны давать аналогичные результаты, хотя, если они равны, инструкция выполняетсямолча.

> identical(sort(unlist(a1)), sort(unlist(b1)))
[1] TRUE
> a1
[[1]]
[1] "PL+"

[[2]]
[1] "PW-"

[[3]]
[1] "PL+"

[[4]]
[1] "PW-"

[[5]]
[1] "PL+" "PW-"

Данные ч / т в @camille для данных.

a1 <- list("PL+", "PW-", "PL+", "PW-", c("PL+", "PW-"))
b1 <- list("PL+", c("PW-", "PL+"), "PL+", "PW-", "PW-")
...