3
$\begingroup$

Supposed that:

list = {2, 3, 5, 7, 9};
sublist = {{3, 3, 5}, {2, 2, 2, 7, 9}};

I want to change each sublist in sublist as following:

  1. Find the positions of elements in sublist in list.So,
{3, 3, 5} -> {2, 2, 3} and {2, 2, 2, 7, 9} -> {1, 1, 1, 4, 5}.
sublist1 = {{2 ,2, 3}, {1, 1, 1, 4, 5}};

2,Change each sublist in sublist1 to sparsearray:

{2, 2, 3} -> {0, 2, 1, 0, 0} and {1, 1, 1, 4, 5} -> {3, 0, 0, 1, 1}.
sublist2 = {{0, 2, 1, 0, 0}, {3, 0, 0, 1, 1}};

How to do it?

$\endgroup$
2
  • $\begingroup$ What should be the length of each last sublist? The same as list's? $\endgroup$
    – Kuba
    Sep 15, 2013 at 22:40
  • $\begingroup$ Yes.Each sublist's length is the same as list. $\endgroup$ Sep 15, 2013 at 22:45

6 Answers 6

4
$\begingroup$

It's perhaps simpler to use rule replacements and the efficient Tally to get the same answer than Position (which is inefficient):

list /. Join[Rule @@@ Tally@#, {_Integer -> 0}] & /@ sublist
(* {{0, 2, 1, 0, 0}, {3, 0, 0, 1, 1}} *)
$\endgroup$
2
  • $\begingroup$ I must say I like it :P but also I think that this will not be the fastest solution for every variation of initial list/sublist. I suppose more answers will appear and someone will make some comparisons :p $\endgroup$
    – Kuba
    Sep 15, 2013 at 23:12
  • $\begingroup$ @Kuba It probably won't be the fastest, but it should be reasonably efficient, since it's not walking through list multiple times. $\endgroup$
    – rm -rf
    Sep 15, 2013 at 23:15
3
$\begingroup$

new - all in one.

Map[Function[x, Count[x, #] & /@ list], sublist]
{{0, 2, 1, 0, 0}, {3, 0, 0, 1, 1}}

old - step by step.

1)

sublist1 = Map[Position[list, #][[1, 1]] &, sublist, {2}]
{{2, 2, 3}, {1, 1, 1, 4, 5}}

2)

sublist2 = SparseArray[Rule @@@ Tally[#], Length@list] & /@ sublist1
{SparseArray[<2>, {5}], SparseArray[<3>, {5}]} 
Normal /@ sublist2
{{0, 2, 1, 0, 0}, {3, 0, 0, 1, 1}}
$\endgroup$
7
  • $\begingroup$ f[list_List, subList_List] := Map[Position[list, #] &, sublist, {Infinity}];? $\endgroup$ Sep 15, 2013 at 22:41
  • $\begingroup$ @belisarius out= {{3, 3, 5}, {2, 2, 2, 7, 9}} something is not ok. $\endgroup$
    – Kuba
    Sep 15, 2013 at 22:43
  • $\begingroup$ Might be more efficient if you do the tally first, since position is generally an inefficient operation: Composition[Normal, SparseArray[#, Length@list]&, Position[list, #][[1, 1]] -> #2 & @@@ # &, Tally] /@ sublist $\endgroup$
    – rm -rf
    Sep 15, 2013 at 22:54
  • $\begingroup$ @rm-rf Thanks for the remark. I've got even shorter code now :) $\endgroup$
    – Kuba
    Sep 15, 2013 at 22:58
  • $\begingroup$ @rm-rf Yes yes, I know, short but not effective with very sparse arrays. $\endgroup$
    – Kuba
    Sep 15, 2013 at 23:02
3
$\begingroup$

Here's another one-liner. Maybe not the fastest, but the most compact yet. I think it also makes it easier to understand what's being done.

Outer[Count,sublist,list,1]

{{0, 2, 1, 0, 0}, {3, 0, 0, 1, 1}}}
$\endgroup$
3
  • $\begingroup$ My apologies but I must condemn this method. I am well known for my fixation on terse code but I cannot excuse this; it is exactly the kind of application that I lamented in Why is there no PositionFunction in Mathematica?. (I mean no offense to you by this; it's nice clean code but I consider it a "siren song" that new users must be warned against.) $\endgroup$
    – Mr.Wizard
    Sep 16, 2013 at 7:18
  • $\begingroup$ @Mr.Wizard I didn't say it was efficient, but I do think it's the clearest statement yet of what is to be done. Perhaps its best use would be in a comment, along with something like "that's what we need, and here's how we get it efficiently." $\endgroup$ Sep 16, 2013 at 12:18
  • $\begingroup$ I agree that it is the clearest code. I think it deserves more than a comment. (You'll notice that I did not down-vote this answer.) I suppose I was overly harsh yesterday, but at the same time I think there is a genuine need for a warning with such things. I think what I'll do, if I have time, is provide timings for the methods posted; then people can see for themselves how these behave without me unfairly singling out your method for criticism. $\endgroup$
    – Mr.Wizard
    Sep 16, 2013 at 16:58
2
$\begingroup$

I presume your starting list will never contain duplicates. Therefore:

1.

sublist1 = sublist /. MapIndexed[#1 -> First[#2] &, list]
(* {{2, 2, 3}, {1, 1, 1, 4, 5}} *)

2.

sublist2 = BinCounts[#, {1, 6, 1}] & /@ sublist1
(* {{0, 2, 1, 0, 0}, {3, 0, 0, 1, 1}} *)
$\endgroup$
2
  • $\begingroup$ BinCounts is/was quite slow in v7; how does it compare to Tally in v9? $\endgroup$
    – Mr.Wizard
    Sep 16, 2013 at 2:43
  • $\begingroup$ @Mr.Wizard been offline for a few days. In my experience BinCounts is usually slow -- I usually look for alternatives if speed is important -- but offered it here as an alternative. Whether it is viable depends on the real data to be used. $\endgroup$ Sep 20, 2013 at 23:15
2
$\begingroup$

Also assuming list is duplicate free I propose this:

sparse[main_][sub_] := Tally[main ~Join~ sub][[All, 2]] - 1

Now:

sparse[list] /@ sublist
{{0, 2, 1, 0, 0}, {3, 0, 0, 1, 1}}

This works by "priming" Tally with the elements of the main list to get the order desired, then subtracting one to correct the totals. SubValues notation is used.


I like the style of the code above but this is slightly faster:

sparse2[main_, sub_] := (Tally[main ~Join~ #][[All, 2]] & /@ sub) - 1

sparse2[list, sublist]
{{0, 2, 1, 0, 0}, {3, 0, 0, 1, 1}}
$\endgroup$
1
$\begingroup$

Just another approach:

Function[u, 
  Reap[Sow[1, #] & /@ u, list, Total@#2 &][[2]] /. {{} -> 0, {x_} :> 
     x}] /@ sublist
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.