Это решение, предложенное Мареком, является лучшим ответом на первоначальный вопрос. См. Ниже обсуждение других подходов и почему Марек является наиболее полезным.
> 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
в списке,Решение Марека состоит в том, чтобы использовать аргумент use.names
для unlist
, что в случае его использования приводит к более быстрому решению, чем приведенная выше двойная уникальная версия.Для простого x
сообщения Романа мы получаем
> unique(unlist(x, use.names = FALSE))
[1] 1 2 3 4 5 6
Решение Марека будет работать, даже если количество уникальных элементов отличается между компонентами.
Вот более крупный пример с некоторыми временамивсе три метода:
## 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's 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's solution:
> system.time(replicate(10, unique(unlist(DF, use.names = FALSE))))
user system elapsed
0.510 0.000 0.512
Что показывает, что удвоение unique
намного быстрее для применения unique()
для отдельных компонентов, а затем unique()
этих меньших наборов уникальных значений, но это ускорение обусловлено только names
в списке DF
.Если мы скажем unlist
не использовать names
, решение Марека будет несколько быстрее, чем двойное unique
для этой проблемы.Поскольку решение Марека правильно использует правильный инструмент, и оно быстрее, чем обходной, оно является предпочтительным решением.
Большая проблема с двойным unique
подходом заключается в том, что он будет работать только если , как в двух примерах, каждый компонент списка ввода (DF
или x
) имеет одинаковое количество уникальных значений.В таких случаях sapply
упрощает результат до матрицы, которая позволяет нам применять unique.default
.Если компоненты входного списка имеют различное количество уникальных значений, двойное уникальное решение завершится неудачей.