Как взять список и сгенерировать все списки увеличивающейся длины? - PullRequest
6 голосов
/ 26 декабря 2011

Любой простой вопрос для экспертов Mathematica здесь:

Имея список, скажем

Clear[a, b, c];
data = {a, b, c};

, и я хочу получить обратно все списки длины 1,2,3,...Length[data], начиная с начала и доконец, так что я получаю следующее для вышеупомянутого

out = {{a}, {a, b}, {a, b, c}}

Я посмотрел на команды в M, чтобы найти готовую для использования, и я мог (посмотрел на все функции Map и Nest *,но не то чтобы я видел как использовать для этого).Я уверен, что это там, но я не вижу его сейчас.

сейчас я делаю этот глупый цикл Do, чтобы построить его

m=Length[data];
First@Reap[Do[Sow[data[[1;;i]]],{i,1,m}]][[2]]

{{a},{a,b},{a,b,c}}

вопрос в том: есть ли у Mathematicaвстроенная команда для выполнения вышесказанного?

обновление 8 часов утра

Я удалил тесты, которые я выполнил несколько часов назад и буду делать репостих снова скоро.Мне нужно запустить их несколько раз и взять среднее значение, так как это лучший способ сделать этот тест производительности.

обновление 9 утра

Хорошо, я перестал- запустить тесты производительности для всех решений, показанных ниже.8 методов.Для каждого метода я запускаю его 5 раз и получаю среднее значение.Я сделал это для n={1000, 5000, 10000, 15000, 25000, 30000}, где n - длина исходного списка для обработки.

не может превышать 30000, будет исчерпан оперативной памяти.У меня только 4 ГБ оперативной памяти.

Я сделал небольшую функцию под названием makeTable[n, methods], которая генерирует таблицу производительности для конкретных n.тестовый код приведен ниже (написан быстро, поэтому не самый чистый код, не очень функциональный, как я должен идти :), но он ниже, и любой может его изменить / очистить и т. д. ... если они хотят

заключение: метод Кгулера был самым быстрым, метод Тиса почти одинаков для больших n (30 000), поэтому для всех практических целей может быть методы Тисса и Кгулера могут быть объявлены победителями для большихп?Но поскольку Kguler также является самым быстрым для малых n, он до сих пор получает четкое преимущество.

Опять же, ниже приведен тестовый код для любого, чтобы проверить и запустить, чтобы посмотреть, не мог ли я где-нибудь сделать ошибку.Как правильно предсказал Леонид, метод связанного списка не слишком хорошо подошел для большого n.

Я думаю, что нужно больше тестов, так как только взятие среднего из 5 может быть недостаточно, и другие соображения, которые я мог бы иметьпропущенный.Это не точный тест, просто грубый, чтобы понять.

Я старался не использовать ПК во время выполнения тестов.Я использовал AbsoluteTiming [] для измерения процессора.

Вот снимок экрана сгенерированных таблиц

enter image description here

Вот код теста:

methods = {nasser, wizard1, wizard2, wizard3, kguler, leonid1, 
   leonid2, thies};
AppendTo[$ContextPath, "Internal`"];
ClearAll[linkedList, leonid2];
SetAttributes[linkedList, HoldAllComplete];

nasser[lst_] := Module[{m = Length[lst]},
   First@Reap[Do[Sow[lst[[1 ;; i]]], {i, 1, m}]][[2]]
   ];

wizard1[lst_] := Module[{},
   Take[lst, #] & /@ Range@Length@lst
   ];

wizard2[lst_] := Module[{},
   Table[Take[#, i], {i, Length@#}] & @lst
   ];

wizard3[lst_] := Module[{},
   Rest@FoldList[Append, {}, #] & @lst
   ];

kguler[lst_] := Module[{},
   Reverse@NestList[Most, #, Length[#] - 1] & @lst

   ];

leonid1[lst_] := Module[{b = Bag[{}]},
   Map[(StuffBag[b, #]; BagPart[b, All]) &, lst]
   ];

leonid2[lst_] := Module[{},
   Map[List @@ Flatten[#, Infinity, linkedList] &, 
    FoldList[linkedList, linkedList[First@lst], Rest@lst]]
   ];

thies[lst_] := 
  Module[{}, 
   Drop[Reverse@
     FixedPointList[If[Length[#] > 0, Most, Identity][#] &, lst], 2]
   ];

makeTable[n_, methods_] := 
  Module[{nTests = Length[methods], nTries = 5, i, j, tests, lst},
   lst = Table[RandomReal[], {n}];

   tests = Table[0, {nTests}, {nTries}];

   For[i = 1, i <= nTests, i++,
    For[j = 1, j <= nTries, j++,
      tests[[i, j]] = First@AbsoluteTiming[methods[[i]][lst] ]
     ]
    ];

   tbl = Table[{ToString[methods[[i]]], Mean[ tests[[i, All]] ]}, {i, 
      nTests}] ;

   Grid[Join[{{"method", "cpu"}}, tbl],
    Frame -> All, FrameStyle -> Directive[Thickness[.005], Gray], 
    Spacings -> {0.5, 1}
    ]
   ];

Теперь, чтобы запустить, сделайте

makeTable[1000, methods]

Предупреждение, не пытайтесь делать что-то более 30000, если у вас есть миллиард ГБ, иначе M может не вернуться.Это случилось со мной, и пришлось перезагрузить компьютер.

обновление 26.12.11 15:30 * * * * * * * * * * Я вижу, что у Thies более новая версия этого алгоритма(Я назвал это thies2 в таблице методов), поэтому я снова все запустил, вот обновленная таблица, я удалил версию связанного списка, поскольку заранее известно, что она не будет быстрой для больших n, и на этот раз язапустить их каждый 10 раз (не 5, как указано выше), а затем взял среднее значение).Я также запустил M заново, используя заводские настройки (перезапустил его, удерживая клавиши Alt-Shift, чтобы на всякий случай все настройки вернулись к исходным настройкам)

вывод пока

Куглер является самым быстрым для меньшего n, то есть n <20000.Для больших n теперь вторая версия Thies быстрее, чем первая версия Thies, и теперь она значительно опережает метод Куглера для больших n.Поздравляем Thies, текущий лидер в этом тесте производительности.Но для практических целей я бы сказал, что методы Thies и Kugler являются самыми быстрыми для больших n, а Kugler остаются самыми быстрыми для меньших n. </p>

Ниже приведены таблицы и обновленный тестовый код под ними.Любой может свободно запускать тесты для себя, на случай, если я что-то упустил.

enter image description here

Текущий код теста:

$MinPrecision = $MachinePrecision;
$MaxPrecision = $MachinePrecision;
methods = {nasser, wizard1, wizard2, wizard3, kguler, leonid, thies1, 
   thies2};
AppendTo[$ContextPath, "Internal`"];

nasser[lst_] := Module[{m = Length[lst]},
   First@Reap[Do[Sow[lst[[1 ;; i]]], {i, 1, m}]][[2]]
   ];

wizard1[lst_] := Module[{},
   Take[lst, #] & /@ Range@Length@lst
   ];

wizard2[lst_] := Module[{},
   Table[Take[#, i], {i, Length@#}] & @lst
   ];

wizard3[lst_] := Module[{},
   Rest@FoldList[Append, {}, #] & @lst
   ];

kguler[lst_] := Module[{},
   Reverse@NestList[Most, #, Length[#] - 1] & @lst

   ];

leonid[lst_] := Module[{b = Bag[{}]},
   Map[(StuffBag[b, #]; BagPart[b, All]) &, lst]
   ];

thies1[lst_] := 
  Module[{}, 
   Drop[Reverse@
     FixedPointList[If[Length[#] > 0, Most, Identity][#] &, lst], 2]
   ];

thies2[lst_] := 
  Module[{}, 
   Drop[Reverse@
     FixedPointList[If[# =!= {}, Most, Identity][#] &, lst], 2]
   ];

makeTable[n_Integer, methods_List] := 
  Module[{nTests = Length[methods], nTries = 10, i, j, tests, lst},
   lst = Table[RandomReal[], {n}];

   tests = Table[0, {nTests}, {nTries}];

   For[i = 1, i <= nTests, i++,
    For[j = 1, j <= nTries, j++,
      tests[[i, j]] = First@AbsoluteTiming[methods[[i]][lst] ]
     ]
    ];

   tbl = Table[{ToString[methods[[i]]], Mean[ tests[[i, All]] ]}, {i, 
      nTests}] ;

   Grid[Join[{{"method", "cpu"}}, tbl],
    Frame -> All, FrameStyle -> Directive[Thickness[.005], Gray], 
    Spacings -> {0.5, 1}
    ]
   ];

Для запусканаберите

n=1000
makeTable[n, methods]

Спасибо всем за ответы, я учился у всех.

Ответы [ 5 ]

7 голосов
/ 26 декабря 2011

Вы можете использовать

f = Reverse@NestList[Most, #, Length[#] - 1] &

f@{a,b,c,d,e} дает {{a}, {a, b}, {a, b, c}, {a, b, c, d}, {a, b, c, d, e}}.

Альтернатива, использующая ReplaceList - намного медленнее, чем f, но ... почему нет?

g = ReplaceList[#, {x__, ___} -> {x}] &
4 голосов
/ 26 декабря 2011

Вот еще один метод, который примерно так же эффективен, как и тот, который включает Take, но использует функциональность Internal`Bag:

AppendTo[$ContextPath, "Internal`"];
runsB[lst_] :=
   Module[{b = Bag[{}]}, Map[(StuffBag[b, #]; BagPart[b, All]) &, lst]];

Я не утверждаю, что он проще, чем основанный нана Take, но, похоже, это простой пример Internal`Bag в действии - поскольку это именно тот тип проблемы, для которого они могут быть успешно использованы (и могут быть случаи, когда списки явных позиций либо не будутдоступно или дорого вычислять).

Для сравнения, решение, основанное на связанных списках:

ClearAll[linkedList, runsLL];
SetAttributes[linkedList, HoldAllComplete];
runsLL[lst_] :=
  Map[List @@ Flatten[#, Infinity, linkedList] &,
    FoldList[linkedList, linkedList[First@lst], Rest@lst]]

будет работать на порядок медленнее в больших списках.

4 голосов
/ 26 декабря 2011

Я предлагаю это:

runs[lst_] := Take[lst, #] & /@ Range@Length@lst

Или это:

runs2 = Table[Take[#, i], {i, Length@#}] &;

Ответ Кгулера вдохновил меня написать это:

Rest@FoldList[Append, {}, #] &

Но этомедленнее, чем его метод из-за медленного добавления Mathematica.

3 голосов
/ 26 декабря 2011

Еще одна идея:

Inits[l_] := Drop[Reverse@FixedPointList[
               If[Length[#] > 0, Most, Identity][#] &,
               l
             ], 2];

Обновление:

Эта версия немного быстрее, если каждый раз не вычислять длину:

Inits2[l_] := Drop[Reverse@FixedPointList[
                If[# =!= {}, Most, Identity][#] &,
                l
              ], 2];
0 голосов
/ 28 декабря 2011

Вероятно, не самый эффективный, но другой подход:

dow[lst_] :=  lst[[1 ;; #]] & /@ Range@Length@lst

Например:

dow[{a, b, c, d, ee}]

дает:

{{a},{a, b}, {a, b, c}, {a, b, c, d}, {a, b, c, d, ee}}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...