可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have listA
and listB
of the same size. I'm doing GatherBy
on listA
, which rearranges that list. What is an elegant way to apply identical rearrangement to listB
?
For example
listA = {1, 2, 3};
listB = {a, b, c};
listA1 = GatherBy[{1, 2, 3}, OddQ];
listB1
should become {{a, c}, {b}}
Update
Thanks for interesting ideas, I eventually ended up doing something similar to belisarius. This reminds me of Python's "decorate-sort-undecorate" pattern
decorated = Thread[{listA, listB}];
grouped = GatherBy[decorated, OddQ[First[#]] &];
listB1 = Map[Last, grouped, {2}]
回答1:
Well, first second try:
(Warning Warning ... "elegance" is an utterly subjective concept)
gBoth[lslave_, lmaster_, f_] :=
{Part[#, All, All, 1], Part[#, All, All, 2]} &@
GatherBy[Transpose[{lslave, lmaster}], f[#[[2]]] &]
lmaster = {1, 2, 3};
lslave = {a, b, c};
{lslave1, lmaster1} = gBoth[lslave, lmaster, OddQ]
Out
{{{a, c}, {b}}, {{1, 3}, {2}}}
Edit
Note that for this code to run you must have
Dimensions[lslave][[1;;Length[Dimensions@lmaster]]] == Dimensions@lmaster
but the deeper internal structure of both lists could be different. For example:
lmaster = {{1, 2, 3}, {2, 3, 4}};
lslave = {{{a}, {b}, {c}}, {{a}, {b}, {c}}};
{lslave1, lmaster1} = gBoth[lslave, lmaster, #[[1]] < 3 &]
Out
{{{{{a}, {b}, {c}}, {{a}, {b}, {c}}}}, {{{1, 2, 3}, {2, 3, 4}}}}
HTH!
回答2:
How about
Map[listB[[#]] &, listA1 /. Dispatch@Thread[listA -> Range[Length[listA]]]]
Edit : It actually came to my mind that this solution will have problems if listA
has repeated elements.Besides, it uses the specialized knowledge that the resulting list is of constant depth 2.
Here is a more general (admittedly, ugly) version, which does not care what is the resulting list structure, or whether the original list did have repeated elements :
Clear[rearrangeAs];
rearrangeAs[source_List, transformed_List, target_List] :=
Module[{f, count, symbs = Table[Unique[], {Length[source]}]},
count[_] = 0;
f[x_, _] := x;
MapThread[With[{cnt = ++count[#1]}, f[#1, cnt] := #2] &, {source, symbs}];
Clear[count];
count[_] = 0;
Replace[transformed, x_ :> f[x, ++count[x]], {0, Infinity}] /.
Dispatch[Thread[symbs -> target]]]
For example,
In[94] := rearrangeAs[listA, listA1, listB]
Out[94] = {{a, c}, {b}}
I did not test, but this function should also work when the transformed list does not have a regular structure, but is some general tree
回答3:
You essentially want:
Map[listB[[#]] &, listA1]
Since ListB[[{1,3,5}]] for example gives a list of the first, third, and fifth elements of ListB.
So this a very simple version of the function:
example[listA_, listB_, ordering_] :=
Map[listB[[#]] &, GatherBy[listA, ordering]]
Its important to note that if a number is duplicated in ListA then it won't appear because of the behavior of GatherBy:
example[{1, 2, 3, 4, 5, 6, 3, 5}, {a, b, c, d, e, f, g, h}, OddQ]
{{a, c, e, c, e}, {b, d, f}}