#arrays #julia #array-broadcasting
#массивы #джулия #массив-широковещательная передача
Вопрос:
У меня есть массив массивов в моем фрейме данных — split.(df2.name)
:
> 392-element Array{Array{SubString{String},1},1}:
["chevrolet", "chevelle", "malibu"]
["buick", "skylark", "320"]
["plymouth", "satellite"]
["amc", "rebel", "sst"]
["ford", "torino"]
⋮
["ford", "mustang", "gl"]
["vw", "pickup"]
["dodge", "rampage"]
["ford", "ranger"]
["chevy", "s-10"]
Я хочу выбрать все элементы каждого массива, кроме первого, и объединить их вместе, чтобы получить названия моделей этих автомобилей.
Сначала я подумал сделать что-то вроде этого: model = join.(split.(df2.name)[2:end], " ")
но вместо удаления первого элемента каждого массива, это удаляет первый car (первый элемент внешнего массива).
Итак, я подумал транслировать диапазон [2:end]
всем элементам, поставив точку непосредственно перед диапазоном: model = join.(split.(df2.name).[2:end], " ")
. Но, похоже, это тоже не работает, потому что возникает синтаксическая ошибка:
syntax: missing last argument in "2:" range expression
Итак, каков джулианский способ широковещания диапазона в таком случае?
Ответ №1:
Кажется, здесь немного сложно использовать обычную широковещательную передачу, поскольку, как вы выяснили, построение 2:end
диапазона явно приводит к синтаксической ошибке. Я думаю, это потому, что выражения типа
a[2:end]
специально проанализированы и сведены к чему-то вроде
a[2:lastindex(a)]
как объяснено в документации для lastindex
.
Однако вы можете использовать итератор, подобный Iterators.drop
, для перебора всех элементов, кроме первого, операция, которая может транслироваться:
julia> cars = [["chevrolet", "chevelle", "malibu"],
["buick", "skylark", "320"],
["plymouth", "satellite"],
["amc", "rebel", "sst"],
["ford", "torino"]];
julia> join.(Iterators.drop.(cars, 1), " ")
5-element Array{String,1}:
"chevelle malibu"
"skylark 320"
"satellite"
"rebel sst"
"torino"
Но я думаю, что в этом случае я бы, вероятно, предпочел понимание, которое, я думаю, было бы более читабельным:
julia> [join(car[2:end], " ") for car in cars]
5-element Array{String,1}:
"chevelle malibu"
"skylark 320"
"satellite"
"rebel sst"
"torino"
РЕДАКТИРОВАТЬ: оглядываясь назад на вашу глобальную проблему, похоже, что сначала вы split
делаете больше, чем хотите, а затем с трудом join
возвращаете части, которые вы не хотели разделять в первую очередь.
Таким образом, вы можете захотеть воспользоваться limit
ключевым аргументом для split
, чтобы в первую очередь не разбивать слишком много слов:
julia> cars2 = ["chevrolet chevelle malibu",
"buick skylark 320",
"plymouth satellite",
"amc rebel sst",
"ford torino"];
julia> split.(cars2, " ", limit=2)
5-element Array{Array{SubString{String},1},1}:
["chevrolet", "chevelle malibu"]
["buick", "skylark 320"]
["plymouth", "satellite"]
["amc", "rebel sst"]
["ford", "torino"]
julia> getindex.(split.(cars2, " ", limit=2), 2)
5-element Array{SubString{String},1}:
"chevelle malibu"
"skylark 320"
"satellite"
"rebel sst"
"torino"
Этот последний пример также демонстрирует, как транслировать синтаксис индексации с помощью явного getindex(a, i)
вызова функции, которая является пониженной формой синтаксического сахара a[i]
.
Ответ №2:
В общем, синтаксис широковещательной индексации работает путем преобразования его в getindex
и трансляции, что:
model = join.(getindex.(split.(df2.name), Ref(2:10)), " ")
Ref
необходим для обработки диапазона как скаляра; вы также можете использовать вместо него 1-кортеж.
Это самая простая часть. Однако этот трюк становится некрасивым в использовании end
, поскольку за пределами скобок он не имеет смысла, что является причиной полученной вами ошибки. Один из способов решить проблему — заменить end
на lastindex
, но тогда вам, вероятно, следует кэшировать вычисление массива:
model = let nameparts = split.(df2.name)
join.(getindex.(nameparts, Ref(2:lastindex(nameparts))), " ")
end
Однако при этом теряется преимущество широковещательного объединения.
В этом конкретном случае вы также могли бы использовать Iterators.rest
, поскольку мы знаем о том, как Array
работают итераторы:
join.(Iterators.rest.(split.(df2.name), 2), " ")
Но самый простой вариант, на мой взгляд, — это просто понимание:
model = [join(split(carname)[2:end]) for carname in df2.name]
(Если вы не очень хорошо знакомы с Iterators
. Тогда я лично предпочел бы предыдущий.)