Вот пример использования Reduce
на языке R.
x <- c(1, 2, 2, 4, 10, 5, 5, 7)
Reduce(\(a, b) if (tail(a, 1) != b) c(a, b) else a, x) # equivalent to `rle(x)$values`
Приведенный выше код предназначен для сортировки извлеченных уникальных значений с точки зрения длины серии, которую можно легко получить с помощью rle(x)$values
.
Я знаю, что в Python есть itertools.groupby
, который выполняет то же самое, что и rle
в R, НО мне интересно следующее: возможно ли получить очень похожий перевод, используя functools.reduce
в Python для достижения той же функциональности, скажем, например
from functools import reduce
x = [1,2,2,4,10,5,5,7]
reduce(lambda a, b: a + [b] if a[-1]!= b else a, x)
но это, к сожалению, дает такие ошибки, как
{
"name": "TypeError",
"message": "'int' object is not subscriptable",
"stack": "---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[58], line 4
1 from functools import reduce
2 x = [1,2,2,4,10,5,5,7]
----> 4 reduce(lambda a, b: a + [b] if a[-1]!= b else a, x)
Cell In[58], line 4, in <lambda>(a, b)
1 from functools import reduce
2 x = [1,2,2,4,10,5,5,7]
----> 4 reduce(lambda a, b: a + [b] if a[-1]!= b else a, x)
TypeError: 'int' object is not subscriptable"
}
Мой вопрос: есть ли в Python какая-нибудь однострочная строка reduce
, похожая на код R?
вы можете использовать список в качестве начального:
from functools import reduce
x = [1,2,2,4,10,5,5,7]
reduce(lambda a, b: a + [b] if a[-1]!= b else a, x, [x[0]])
[1, 2, 4, 10, 5, 7]
Обратите внимание, что вы можете использовать groupby из itertools
:
from itertools import groupby
[i for i,j in groupby(x)]
[1, 2, 4, 10, 5, 7]
Инициализатор [x[0]] помещается перед элементами итерируемого объекта в вычислении. В противном случае мы можем столкнуться с a + [b], где a — это просто целое число, не имеющее смысла.
Вот еще одно решение, чтобы подчеркнуть разницу. В R скаляр также является вектором длины 1, поэтому у Tail() или c() нет проблем, в то время как в Python нет концепции скаляра[-1] или скаляра + списка.
def foo(a,b):
if (isinstance(a, int)): return [a]
elif a[-1] != b: return a + [b]
else: return a
reduce(foo, x)
[1, 2, 4, 10, 5, 7]
тоже отличное решение, +1, а также спасибо за объяснение
да, хороший трюк для решения проблемы + 1. Не могли бы вы немного объяснить, почему здесь нужен начальный
[x[0]]
?