Найдите набор дубликатов
dups = MyString[ duplicated(MyString) ]
и отбросьте все вхождения в наборе
MyString[ !MyString %in% dups ]
Альтернатива:
setdiff(MyString, dups)
Основанное на таблице решение из@Moody_Mudskipper обеспечивает большую гибкость, например, для выбора строк, которые встречаются дважды.Альтернативно (возможно, быстрее, чем аналогичные table()
-разрешения, когда длина MyString
длинная), но создать индекс для уникальных строк, найти число совпадений каждой уникальной строки (tabulate() == 1
) и использовать их дляподмножество уникальных строк:
UString = unique(MyString)
UString[ tabulate(match(MyString, UString)) == 1 ]
или сохраните необходимость создания UString
MyString[ which(tabulate(match(MyString, MyString)) == 1) ]
Альтернатива: сортировка и затем поиск прогонов длиной 1.
r = rle(sort(MyString))
r$values[ r$lengths == 1 ]
Для производительности, вот некоторые функции, реализующие различные решения
f0 = function(x) x[ !x %in% x[duplicated(x)] ]
f1 = function(x) setdiff( x, x[duplicated(x)] )
f2 = function(x) { ux = unique(x); ux[ tabulate(match(x, ux)) == 1 ] }
f3 = function(x) x[ which( tabulate( match(x, x) ) == 1 ) ]
f4 = function(x) { r = rle(sort(x)); r$values[ r$lengths == 1] }
f5 = function(x) { x = table(x); names(x)[x==1] }
f6 = function(x) x[ !duplicated(x) & !duplicated(x, fromLast = TRUE) ]
, свидетельствующие о том, что они дают идентичные результаты
> identical(f0(x), f1(x))
[1] TRUE
> identical(f0(x), f2(x))
[1] TRUE
> identical(f0(x), f3(x))
[1] TRUE
> identical(f0(x), f4(x))
[1] TRUE
> identical(f0(x), f5(x))
[1] TRUE
> identical(f0(x), f6(x))
[1] TRUE
f5()
(также в исходной реализации) не удается для x = character(0)
> f1(character(0))
character(0)
> f5(character(0))
NULL
f4()
и f5()
возвращают значения в алфавитном порядке, в то время как остальные сохраняют порядок на входе, например unique()
.Все методы, кроме f5()
, работают с векторами другого типа, например, integer()
(f5()
всегда возвращает символьный вектор, другие возвращают вектор того же типа, что и входные данные).f4()
и f5()
не распознают уникальные вхождения NA
.
и время:
> microbenchmark(f0(x), f1(x), f2(x), f3(x), f4(x), f5(x), f6(x))
Unit: microseconds
expr min lq mean median uq max neval
f0(x) 9.195 10.9730 12.35724 11.8120 13.0580 29.100 100
f1(x) 20.471 22.6625 50.15586 24.6750 25.9915 2600.307 100
f2(x) 13.708 15.2265 58.58714 16.8180 18.4685 4180.829 100
f3(x) 7.533 8.8775 52.43730 9.9855 11.0060 4252.063 100
f4(x) 74.333 79.4305 124.26233 83.1505 87.4455 4091.371 100
f5(x) 147.744 154.3080 196.05684 158.4880 163.6625 3721.522 100
f6(x) 12.458 14.2335 58.11869 15.4805 17.0440 4250.500 100
Вот производительность с 10 000 уникальных слов
> x = readLines("/usr/share/dict/words", 10000)
> microbenchmark(f0(x), f1(x), f2(x), f3(x), f4(x), f5(x), f6(x), times = 10)
Unit: microseconds
expr min lq mean median uq max neval
f0(x) 848.086 871.359 880.8841 873.637 899.669 916.528 10
f1(x) 1440.904 1460.704 1556.7154 1589.405 1607.048 1640.347 10
f2(x) 2143.997 2257.041 2288.1878 2288.329 2334.494 2372.639 10
f3(x) 1420.144 1548.055 1547.8093 1562.927 1596.574 1601.176 10
f4(x) 11829.680 12141.870 12369.5407 12311.334 12716.806 12952.950 10
f5(x) 15796.546 15833.650 16176.2654 15858.629 15913.465 18604.658 10
f6(x) 1219.036 1356.807 1354.3578 1363.276 1372.831 1407.077 10
И с существенным дублированием
> x = sample(head(x, 1000), 10000, TRUE)
> microbenchmark(f0(x), f1(x), f2(x), f3(x), f4(x), f5(x), f6(x))
Unit: milliseconds
expr min lq mean median uq max neval
f0(x) 1.914699 1.922925 1.992511 1.945807 2.030469 2.246022 100
f1(x) 1.888959 1.909469 2.097532 1.948002 2.031083 5.310342 100
f2(x) 1.396825 1.404801 1.447235 1.420777 1.479277 1.820402 100
f3(x) 1.248126 1.257283 1.295493 1.285652 1.329139 1.427220 100
f4(x) 24.075280 24.298454 24.562576 24.459281 24.700579 25.752481 100
f5(x) 4.044137 4.120369 4.307893 4.174639 4.283030 7.740830 100
f6(x) 1.221024 1.227792 1.264572 1.243201 1.295888 1.462007 100
f0()
кажется победителем скорости, когда дубликаты редки
> x = readLines("/usr/share/dict/words", 100000)
> microbenchmark(f0(x), f1(x), f3(x), f6(x))
Unit: milliseconds
expr min lq mean median uq max neval
f0(x) 11.03298 11.17124 12.17688 11.36114 11.62769 19.83124 100
f1(x) 21.16154 21.33792 22.76237 21.67234 22.26473 31.99544 100
f3(x) 21.15801 21.49355 22.60749 21.77821 22.54203 31.17288 100
f6(x) 18.72260 18.97623 20.29060 19.46875 19.94892 28.17551 100
f3()
и f6()
выглядят правильно и быстро;f6()
, вероятно, легче понять (но обрабатывает только особый случай сохранения слов, которые встречаются ровно один раз).