Fast extraction of elements from nested lists - wolfram-mathematica

This is a basic question on list manipulation in Mathematica.
I have a large list where each element has the following schematic form: {List1, List2,Number}. For e.g.,
a = {{{1,2,3},{1,3,2},5},{{1,4,5},{1,0,2},10},{{4,5,3},{8,3,4},15}}}.
I want to make a new lists which only has some parts from each sublist. Eg., pick out the third element from each sublist to give {5,10,15} from the above. Or drop the third element to return {{{1,2,3},{1,3,2}},{{1,4,5},{1,0,2}},{{4,5,3},{8,3,4}}}.
I can do this by using the table command to construct new lists, e.g.,
Table[a[[i]][[3]],{i,1,Length[a]}
but I was wondering if there was a must faster way which would work on large lists.

In Mathematica version 5 and higher, you can use the keyword All in multiple ways to specify a list traversal.
For instance, instead of your Table, you can write
a[[All,3]]
Here Mathematica converts All into all acceptable indices for the first dimension then takes the 3rd one of the next dimension.
It is usually more efficient to do this than to make a loop with the Mathematica programming language. It is really fine for homogenous lists where the things you want to pick or scan through always exist.
Another efficient notation and shortcut is the ;; syntax:
a[[ All, 1 ;; 2]]
will scan the first level of a and take everything from the 1st to the 2st element of each sublist, exactly like your second case.
In fact All and ;; can be combined to any number of levels. ;; can even be used in a way similar to any iterator in Mathematica:
a[[ start;;end;;step ]]
will do the same things as
Table[ a[[i]], {i,start,end,step}]
and you can omit one of start, end or step, it is filled with its default of 1, Length[(of the implicit list)], and 1.
Another thing you might want to lookup in Mathematica's Help are ReplacePart and MapAt that allow programmatic replacement of structured expressions. The key thing to use this efficiently is that in ReplacePart you can use patterns to specify the coordinates of the things to be replaced, and you can define functions to apply to them.
Example with your data
ReplacePart[a, {_, 3} -> 0]
will replace every 3rd part of every sublist with 0.
ReplacePart[a, {i : _, 3} :> 2*a[[i, 3]]]
will double every 3rd part of every sublist.

As the authors suggest, the approaches based on Part need well-formed data, but Cases is built for robust separation of Lists:
Using your a,
a = {{{1, 2, 3}, {1, 3, 2}, 5}, {{1, 4, 5}, {1, 0, 2},
10}, {{4, 5, 3}, {8, 3, 4}, 15}};
Cases[a,{_List,_List,n_}:>n,Infinity]
{5, 10, 15}
The other pieces of a record can be extracted by similar forms.
Part-based approaches will gag on ill-formed data like:
badA = {{{1, 2, 3}, {1, 3, 2}, 5}, {{1, 4, 5}, {1, 0, 2},
10}, {{4, 5, 3}, {8, 3, 4}, 15}, {baddata}, {{1, 2, 3}, 4}};
badA[[All,3]]
{{{1, 2, 3}, {1, 3, 2}, 5}, {{1, 4, 5}, {1, 0, 2},
10}, {{4, 5, 3}, {8, 3, 4}, 15}, {baddata}, {{1, 2, 3},
4}}[[All, 3]]
,but Cases will skip over garbage, operating only on conforming data
Cases[badA, {_List, _List, s_} :> s, Infinity]
{5, 10, 15}
hth,
Fred Klingener

You can use Part (shorthand [[...]]) for this :
a[[All, 3]]
a[[All, {1, 2}]]

Related

binning an array to create sum domains array

In Mathematica - how do I bin an array to create a new array which consist from sum domains of the old array with a given size ???
Example:
thanks.
This is slightly simpler than #ChrisDegnen's solution. Given the same definition of array the expression
Map[Total, Map[Flatten, Partition[array, {2, 2}], {2}], {2}]
produces
{{4, 10}, {8, 10}}
If you prefer, this expression
Apply[Plus, Map[Flatten, Partition[array, {2, 2}], {2}], {2}]
uses Apply and Plus rather than Map and Total but is entirely equivalent.
This works for the example but a generalised version would need more work.
array =
{{1, 1, 1, 2},
{1, 1, 3, 4},
{2, 2, 2, 3},
{2, 2, 2, 3}};
Map[Total,
Map[Flatten,
Map[Transpose,
Map[Partition[#, 2] &, Partition[array, 2], 2],
2], {2}], {2}]
% // MatrixForm
4 10
8 10

Algorithm for nesting nesting sets

I have a large collection of sets, some of which are subsets of each others, like:
[{1, 2, 3, 4}, {1, 2}, {1, 5}, {1, 2, 3, 4, 5}, {2, 6}]
I'd like to take this collection and output a DAG of partial order of the subset relations
{1, 2, 3, 4, 5} >= {1, 2, 3, 4} >= {1, 2}
{1, 2, 3, 4, 5} >= {1, 5}
{2, 6}
Is there a way to do this other than comparing all combinations of sets (which is prohibitive when there is a large number of sets). This seems close to a number of set cover problems but, I can't find a problem that this reduces to.
One optimization is to create an inverted index which would help avoid comparing sets that had no common element like {2, 6} and {1, 5}.
This problem seems related to Topological sorting and Linear Extensions of a partial order.
This is nearly a duplicate of Generate a DAG from a poset using stricly functional programming, but I'm open to a solution that is not purely functional.

How to create a Mathematica list of fewer columns from larger list of many columns

I have a list "data1":
{{1, 6, 4.5, 1, 141.793, 2.31634, 27.907}, {2, 7, 4.5, 1, 133.702,
2.28725, 26.7442}, {3, 5, 5, 1, 136.546, 2.33522, 25.5814}, {4, 8,
5, 1, 104.694, 2.27871, 24.4186}}
What I would like to do is to create a new table with only the first two columns of each element. So my new table would be:
{{1,6},{2,7},{3,5},{4,8}}
I tried
data1[[All, 1][All, 2]]
and other variations but I am not understanding how to capture the desired fields. Thank you for your help.
Just have a range or list of the indices you want as the second argument, like so:
In[71]:= data[[All, {1, 2}]]
Out[71]= {{1, 6}, {2, 7}, {3, 5}, {4, 8}}

How to do Tally-like operation on list based on elements' total in Mathematica

For example, I have a list like:
{{1, 2, 3}, {6}, {4, 5}, {1, 6}, {2, 2, 3, 2}, {9}, {7}, {2, 5}}
And I want to get a tallied list based on the total of the lists' elements.
In this case, I want the output to be:
{{6, {{1, 2, 3}, {6}}, {7, {{2, 5}, {1, 6}, {7}}}, {9, {{4, 5}, {2, 2, 3, 2}, {9}}}}}
How to do this conveniently in Mathematica?
Thanks a lot.
Here's my attempt - a little simpler than Yoda's
lst = {{1, 2, 3}, {6}, {4, 5}, {1, 6}, {2, 2, 3, 2}, {9}, {7}, {2, 5}};
{Total#First##, #} & /# GatherBy[lst, Total]
If you don't want repeated elements, then you could use
{Total#First##, Union[#]} & /# GatherBy[lst, Total]
Or if you really wanted a tally-like operation
{Total#First##, Tally[#]} & /# GatherBy[lst, Total]
While I would probably do this just as #Simon did, let us not forget that Reap and Sow can be used as well:
Reap[Sow[#, Total[#]] & /# lst, _, List][[2]]
where lst is the original list. This will be somewhat less efficient than the GatherBy- based code, but also pretty fast. One can speed up the above code about 1.5 times by rewriting it as
Reap[Sow ### Transpose[{lst, Total[lst, {2}]}], _, List][[2]]
in which case it becomes about 1.5 times slower than the code based on GatherBy. Note that the speed difference between the two methods is not very dramatic here, because the list is ragged and therefore not packed, and GatherBy does not have here the speed advantage it normally enjoys for packed arrays.
Don't overlook Tr. This is shorter and faster:
{Tr##, {##}} & ### GatherBy[lst, Tr]

two list operations in mathematica

I have two list operations which I would like to ask for help. The way I implemented them is not very elegant, so I want to learn from you experts.
1) Suppose I have two lists, one is like {{0,2,4},{1,3,2},{2,0,4}} and the other is {{1,3,7},{2,4,6},{3,1,9}}. I want to either based on the value, or based on some criterion to filter through the first list, and then get the corresponding elements in the second. For example, based on value which is non-zero, I want to get {{3,7},{2,4,6},{3,9}}. Based on the condition greater than 2, I want to get {{7},{4},{9}}.
2) I have a list such as {{{1,2},{1,1}},{{1,3},{2,4}},{{1,2},{2,3}},{{1,4},{3,3}}}. I want to form {{{1,2},{{1,1},{2,3}}},{{1,3},{{2,4}}},{{1,4},{{3,3}}}. That is, I want to group those second lists if the first element is the same. How can I do this in a beautiful way?
Many thanks.
For the first part, you want Pick:
In[27]:= Pick[{{1,3,7},{2,4,6},{3,1,9}},{{0,2,4},{1,3,2},{2,0,4}},_?Positive]
Out[27]= {{3,7},{2,4,6},{3,9}}
In[28]:= Pick[{{1,3,7},{2,4,6},{3,1,9}},{{0,2,4},{1,3,2},{2,0,4}},_?(#>2&)]
Out[28]= {{7},{4},{9}}
For the second question, GatherBy gets you most of the way there:
In[29]:= x = GatherBy[{{{1, 2}, {1, 1}}, {{1, 3}, {2, 4}}, {{1, 2},
{2, 3}}, {{1, 4}, {3, 3}}}, First]
Out[29]= {{{{1, 2}, {1, 1}}, {{1, 2}, {2, 3}}}, {{{1, 3},
{2, 4}}}, {{{1, 4}, {3, 3}}}}
And then you can apply a rule to clean things up a bit:
In[30]:= x /. l:{{a_, _}..} :> {a, Last /# l}
Out[30]= {{{1, 2}, {{1, 1}, {2, 3}}}, {{1, 3}, {{2, 4}}},
{{1, 4}, {{3, 3}}}}
As Michael said, Pick is definitely the way to go for the first one.
For the second part, I'd like to offer an alternative that lets you do this in one line: SelectEquivalents. (I know, rather self promoting, but I use this function a lot.) To get the result your looking for, simply enter
In[1] := SelectEquivalents[ <list>, First, Last, {#1,#2}& ]
Out[1]:= {{{1, 2}, {{1, 1}, {2, 3}}}, {{1, 3}, {{2, 4}}}, {{1, 4}, {{3, 3}}}}
Internally, SelectEquivalents uses Reap and Sow, so First tags each element in <list>, Last transforms the element into the form we wish to use, and {#1, #2}& returns a list with elements of the form {Tag, {<items with that tag>}}. The advantage is that you get to specify everything in one step getting you what you want without subsequent transformations.

Resources