В некоторой степени поведение, которое вы видите, следует ожидать. PARI передает списки и карты по значению, а не по ссылке, за исключением специальных встроенных функций для управления ими. Это можно увидеть, создав функцию-оболочку, например mylistput(list,item)=listput(list,item);
. Когда вы попытаетесь использовать эту функцию, вы обнаружите, что она не работает, потому что она работает с копией списка. Возможно, это ошибка в PARI, но, возможно, у них есть свои причины. Результатом этого поведения является то, что каждый раз, когда вы добавляете элемент в один из списков, хранящихся на карте, весь список копируется, возможно, дважды.
Ниже приведено решение, позволяющее избежать этой проблемы.
sparsearray(n,myfun=(x)->x)=
{
my(vi=vector(n, i, i)); \\ input values
my(vo=vector(n, i, myfun(vi[i]))); \\ output values
my(perm=vecsort(vo,,1)); \\ obtain order of output values as a permutation
my(list=List(), bucket=List(), key);
for(loop=1, #perm,
if(loop==1||vo[perm[loop]]<>key,
if(#bucket, listput(list,[key,Vec(bucket)]);bucket=List()); key=vo[perm[loop]]);
listput(bucket,vi[perm[loop]])
);
if(#bucket, listput(list,[key,Vec(bucket)]));
Mat(Col(list))
}
Выходные данные - это матрица в том же формате, что и карта - если вы предпочитаете карту, ее можно преобразовать с помощью Map(...)
, но вы, вероятно, захотите матрицу для обработки, поскольку на карте нет встроенной функции получить список ключей.
Я немного переработал вышесказанное, чтобы попытаться сделать что-то более похожее на GroupBy в C #. (функция, которая может быть полезна для многих вещей)
VecGroupBy(v, f)={
my(g=vector(#v, i, f(v[i]))); \\ groups
my(perm=vecsort(g,,1));
my(list=List(), bucket=List(), key);
for(loop=1, #perm,
if(loop==1||g[perm[loop]]<>key,
if(#bucket, listput(list,[key,Vec(bucket)]);bucket=List()); key=g[perm[loop]]);
listput(bucket, v[perm[loop]])
);
if(#bucket, listput(list,[key,Vec(bucket)]));
Mat(Col(list))
}
Вы бы использовали это как VecGroupBy([1..300],i->i%7)
.