Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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?

share|improve this question
    
What should be the length of each last sublist? The same as list's? –  Kuba Sep 15 '13 at 22:40
    
Yes.Each sublist's length is the same as list. –  incognito007 Sep 15 '13 at 22:45
add comment

6 Answers 6

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}}}
share|improve this answer
    
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 7: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
add comment

Just another approach:

Function[u, 
  Reap[Sow[1, #] & /@ u, list, Total@#2 &][[2]] /. {{} -> 0, {x_} :> 
     x}] /@ sublist
share|improve this answer
add comment

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}}
share|improve this answer
add comment

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}} *)
share|improve this answer
    
BinCounts is/was quite slow in v7; how does it compare to Tally in v9? –  Mr.Wizard Sep 16 '13 at 2: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
add comment

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}}
share|improve this answer
    
f[list_List, subList_List] := Map[Position[list, #] &, sublist, {Infinity}];? –  belisarius Sep 15 '13 at 22:41
    
@belisarius out= {{3, 3, 5}, {2, 2, 2, 7, 9}} something is not ok. –  Kuba Sep 15 '13 at 22:43
    
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 –  rm -rf Sep 15 '13 at 22:54
    
@rm-rf Thanks for the remark. I've got even shorter code now :) –  Kuba Sep 15 '13 at 22:58
    
@rm-rf Yes yes, I know, short but not effective with very sparse arrays. –  Kuba Sep 15 '13 at 23:02
show 2 more comments

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}} *)
share|improve this answer
    
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
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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