Ответ 1
Это решение, предложенное Мареком, является лучшим ответом на исходный Q. См. ниже обсуждение других подходов и почему Marek является наиболее полезным.
> unique(unlist(x, use.names = FALSE))
[1] 1 2 3 4 5 6
Обсуждение
Более быстрое решение состоит в том, чтобы сначала вычислить unique()
на компонентах вашего x
, а затем сделать окончательный unique()
по этим результатам. Это будет работать, только если компоненты списка имеют одинаковое количество уникальных значений, как в обоих примерах ниже. Например:.
Сначала ваша версия, затем мой двойной уникальный подход:
> unique(unlist(x))
[1] 1 2 3 4 5 6
> unique.default(sapply(x, unique))
[1] 1 2 3 4 5 6
Нам нужно вызвать unique.default
, поскольку существует метод matrix
для unique
, который фиксирует один край фиксированного; это прекрасно, так как матрица может рассматриваться как вектор.
Марек в комментариях к этому ответу отмечает, что медленная скорость подхода unlist
потенциально связана с names
в списке. Решение Marek должно использовать аргумент use.names
для unlist
, который, если используется, приводит к более быстрому решению, чем двойная уникальная версия выше. Для простого x
римского поста получаем
> unique(unlist(x, use.names = FALSE))
[1] 1 2 3 4 5 6
Решение Marek будет работать, даже если количество уникальных элементов различается между компонентами.
Вот пример с несколькими таймингами всех трех методов:
## Create a large list (1000 components of length 100 each)
DF <- as.list(data.frame(matrix(sample(1:10, 1000*1000, replace = TRUE),
ncol = 1000)))
Ниже приведены результаты для двух подходов с использованием DF
:
> ## Do the three approaches give the same result:
> all.equal(unique.default(sapply(DF, unique)), unique(unlist(DF)))
[1] TRUE
> all.equal(unique(unlist(DF, use.names = FALSE)), unique(unlist(DF)))
[1] TRUE
> ## Timing Roman original:
> system.time(replicate(10, unique(unlist(DF))))
user system elapsed
12.884 0.077 12.966
> ## Timing double unique version:
> system.time(replicate(10, unique.default(sapply(DF, unique))))
user system elapsed
0.648 0.000 0.653
> ## timing of Marek solution:
> system.time(replicate(10, unique(unlist(DF, use.names = FALSE))))
user system elapsed
0.510 0.000 0.512
Что показывает, что двойной unique
намного быстрее применяет unique()
к отдельным компонентам, а затем unique()
эти меньшие множества уникальных значений, но это ускорение происходит исключительно из-за names
on список DF
. Если мы скажем unlist
не использовать names
, решение Марека будет немного быстрее, чем двойное unique
для этой проблемы. Поскольку решение Marek правильно использует правильный инструмент, и оно быстрее, чем обход, это предпочтительное решение.
Большая getcha с двойным подходом unique
заключается в том, что она будет работать только , если, как в двух примерах здесь, каждый компонент списка ввода (DF
или x
) имеет такое же количество уникальных значений. В таких случаях sapply
упрощает результат до матрицы, которая позволяет применить unique.default
. Если компоненты входного списка имеют разные числа уникальных значений, двойное уникальное решение не будет выполнено.