Диапазоны вещания

#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 . Тогда я лично предпочел бы предыдущий.)