3

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?

m_goldberg
  • 107,779
  • 16
  • 103
  • 257
incognito007
  • 251
  • 1
  • 5

6 Answers6

4

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}} *)
rm -rf
  • 88,781
  • 21
  • 293
  • 472
  • 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 – Kuba Sep 15 '13 at 23:12
  • @Kuba It probably won't be the fastest, but it should be reasonably efficient, since it's not walking through list multiple times. – rm -rf Sep 15 '13 at 23:15
3

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}}
Kuba
  • 136,707
  • 13
  • 279
  • 740
3

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}}}
Ray Koopman
  • 3,306
  • 14
  • 13
  • 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.) – Mr.Wizard Sep 16 '13 at 07:18
  • @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." – Ray Koopman Sep 16 '13 at 12:18
  • 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. – Mr.Wizard Sep 16 '13 at 16:58
2

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}} *)
Mike Honeychurch
  • 37,541
  • 3
  • 85
  • 158
  • BinCounts is/was quite slow in v7; how does it compare to Tally in v9? – Mr.Wizard Sep 16 '13 at 02:43
  • @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. – Mike Honeychurch Sep 20 '13 at 23:15
2

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}}
Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
1

Just another approach:

Function[u, 
  Reap[Sow[1, #] & /@ u, list, Total@#2 &][[2]] /. {{} -> 0, {x_} :> 
     x}] /@ sublist
ubpdqn
  • 60,617
  • 3
  • 59
  • 148