Создание частичного массива в Perl6 - PullRequest
0 голосов
/ 25 июня 2018

Есть ли хороший способ получить частичный массив, полученный из другого массива?

Пример: для данного массива с x количеством элементов и Int $index в пределах диапазона элементов этого массива, Iхотел бы запустить функцию от $index + 1 до количества элементов - 1.

По сути, я хотел бы сравнить все элементы в массиве.Сравните, будучи функцией самого элемента.(Обратите внимание, я знаю о функции eqv, хотя она не подходит для данной конкретной ситуации)

Я думал о чем-то вроде:

for $!my-array.kv -> $index, $element
{
    for $!my-array[$index+1 .. .elems-1] -> $another-element
    {
        $element.compare($another-element)
    }
}

Ответы [ 2 ]

0 голосов
/ 25 июня 2018

.elems - 1 вызывает метод для $_, что, вероятно, неправильно.
Если вы собираетесь написать это так $!my-array.elems - 1, или вы можете задать лямбду *.elems - 1. Обычная лямбда равна * - 1 (массив нумеруется до количества элементов).
В этом случае я бы просто использовал Whither *.

$!my-array[$index + 1 .. *]

Чтобы for вернул результат, добавьте к нему префикс do.

my @result = do for $!my-array.kv -> $index, $element
{

    do for $!my-array[$index + 1 .. *] -> $another-element
    {
        $element.compare($another-element)
    }
}

Возможно, будет понятнее использовать map

$!my-array.kv.map: -> $index, $element {

  $!my-array[$index + 1 .. *].map: -> $another-element {

    $element.compare($another-element)
  }
}

Поскольку вы упоминаете, что eqv не подходит, это заставляет меня поверить, что .compare возвращает True, когда они эквивалентны, и False в противном случае.
Так что тогда eqv на самом деле подходит . Вам просто нужно сначала его настроить.

class Foo {
    method compare (Foo:D: Foo:D $other ) {…}
    …
}

# this gets mixed into the existing &infix:«eqv»
# mark it for export so that it is available in other code units
multi sub infix:«eqv» ( Foo:D \left, Foo:D \right ) is export {

  left.compare(right)

}
# must import it everywhere you want the special cased &infix:«eqv»
# as operators are lexically scoped
use Foo;

$!my-array.kv.map: -> $index, $element {
    # cross using &infix:«eqv»
    $element X[eqv] $!my-array[$index + 1 .. *]
}

Вы также можете использовать «eqv« (<<eqv<<).


То, что вы написали, довольно близко совпадает с combinations.

my @result = $!my-array.combinations(2).map(
  -> ( $a, $b ) { $a eqv $b }
)

Это дает плоский список.

< a b c d e >.combinations(2).map: -> ($element, $another-element){
    $element cmp $another-element
}
# (Less,Less,Less,Less,Less,Less,Less,Less,Less,Less)

Пока предыдущий код выдает список списков. (с лишним пустым)

my @a = < a b c d e >;
say @a.kv.map: -> $index, $value {
  @a[$index ^.. *].map: $value cmp *
}
# (
#   (Less,Less,Less,Less),
#   (Less,Less,Less),
#   (Less,Less),
#   (Less,),
#   (),
# )

Обратите внимание, что вы можете записать имя инфиксного оператора eqv несколькими способами

&infix:«  eqv  »
&infix:<  eqv  >
&infix:[ 'eqv' ]
&[eqv]

Все, кроме последнего, можно использовать при объявлении новой реализации multi sub.
(после удаления &)


P.S. Я думаю, что метод с именем .compare должен вернуть Order (Less, Same, More).
Таким образом, правильный оператор для настройки будет &infix:«cmp».

0 голосов
/ 25 июня 2018

Вы можете избежать двойной петли for, используя combinations.Если вы не хотите записывать индексы, это может быть просто:

for @($!my-array).combinations: 2 -> ( $element, $another-element ) {
    $element.compare($another-element);
}
...