4
$\begingroup$

I have a list, which contains more lists with elements, see example {{1, 1, 1, 1, 2}, {2, 2, 2, 2, 3}, {3, 3, 3, 4, 3}}

I want to remove num 2 from the first list and num 3 from the second list and num 4 from the third list. Suppose i don't know the value of the element and don't know the position of the element i want to remove. I want the function or whatever to return {{x,x,x,x},{y,y,y,y},{z,z,z,z}}

Is it possible to do this in Mathematica?

$\endgroup$
  • 2
    $\begingroup$ So what is really the case? Is there always only one element which is different? $\endgroup$ – Kuba Nov 17 '15 at 13:25
  • $\begingroup$ Welcome to Mathematica.SE! I suggest the following: 1) As you receive help, try to give it too, by answering questions in your area of expertise. 2) Take the tour! 3) When you see good questions and answers, vote them up by clicking the gray triangles, because the credibility of the system is based on the reputation gained by users sharing their knowledge. Also, please remember to accept the answer, if any, that solves your problem, by clicking the checkmark sign! $\endgroup$ – Michael E2 Nov 17 '15 at 13:42
12
$\begingroup$
Most @ CommonestFilter[#, 2] & /@ data

when all initial sublists have the same length you could skip Map:

CommonestFilter[
  data,
  {0, 2}
  ][[;; , 2 ;;]]
$\endgroup$
  • $\begingroup$ Wow, I've never heard of either of those functions $\endgroup$ – Jason B. Nov 17 '15 at 13:49
  • $\begingroup$ @JasonB You are welcome. :) Well it's the first time I'm using this filter too :) $\endgroup$ – Kuba Nov 17 '15 at 13:51
3
$\begingroup$
(Gather /@ {{1, 1, 1, 1, 2}, {2, 2, 2, 2, 3}, {3, 3, 3, 4, 
     3}, {8, 8, 7, 8, 8}})[[All, 1]]
(* {{1, 1, 1, 1}, {2, 2, 2, 2}, {3, 3, 3, 3}, {8, 8, 8, 8}} *)

Will work so long as the element you want to keep is first in the list, but it fails here

(Gather /@ {{1, 1, 1, 1, 2}, {2, 2, 2, 2, 3}, {3, 3, 3, 4, 
     3}, {8, 8, 7, 8, 8}, {4, 9, 9, 9, 9}})[[All, 1]]
(* {{1, 1, 1, 1}, {2, 2, 2, 2}, {3, 3, 3, 3}, {8, 8, 8, 8}, {4}} *)

So first use Gather, then sort by Length, so that you are choosing the list with the most number of elements.

This function does the trick

removeoddelement[list_] := Last@SortBy[Gather[list], Length]

removeoddelement@{11, 11, 90, 11, 11}
(* {11, 11, 11, 11} *)

removeoddelement /@ {{192, 12, 12, 12, 12}, {118, 0, 0, 0, 
   0}, {2, 2, 2, 165, 2}, {3, 3, 3, 3, 112}, {113, 14, 14, 14, 
   14}, {14, 91, 14, 14, 14}, {5, 5, 5, 5, 150}, {6, 6, 6, 186, 
   6}, {5, 5, 5, 108, 5}, {15, 15, 15, 151, 15}, {10, 10, 10, 76, 
   10}, {3, 3, 3, 174, 3}, {14, 162, 14, 14, 14}, {7, 139, 7, 7, 
   7}, {4, 4, 73, 4, 4}, {115, 14, 14, 14, 14}, {135, 10, 10, 10, 
   10}, {1, 1, 1, 119, 1}, {7, 165, 7, 7, 7}, {5, 5, 149, 5, 5}}
(* {{12, 12, 12, 12}, {0, 0, 0, 0}, {2, 2, 2, 2}, {3, 3, 3, 
  3}, {14, 14, 14, 14}, {14, 14, 14, 14}, {5, 5, 5, 5}, {6, 6, 6, 
  6}, {5, 5, 5, 5}, {15, 15, 15, 15}, {10, 10, 10, 10}, {3, 3, 3, 
  3}, {14, 14, 14, 14}, {7, 7, 7, 7}, {4, 4, 4, 4}, {14, 14, 14, 
  14}, {10, 10, 10, 10}, {1, 1, 1, 1}, {7, 7, 7, 7}, {5, 5, 5, 5}} *)
$\endgroup$
  • $\begingroup$ It worked, thank you! $\endgroup$ – gneken Nov 17 '15 at 13:32
2
$\begingroup$
list = {1, 1, 2, 2, 1, 2, 2};

ConstantArray[#, Count[list, #]] &[First @ Commonest[list, 1]]

{2, 2, 2, 2}

$\endgroup$
  • 2
    $\begingroup$ or Cases[list,First@Commonest@list] $\endgroup$ – SquareOne Nov 17 '15 at 23:16
1
$\begingroup$

You can do this with a pipeline of curried functions, like so:

In[1]:= Map[
         Counts /* TakeLargest[1] /* KeyValueMap[ConstantArray] /* Flatten, 
         rows]
Out[1]= {{1, 1, 1, 1}, {2, 2, 2, 2}, {3, 3, 3, 3}}

That keeps the most common element. This will delete any singleton elements:

In[2]:= Map[
         Counts /* DeleteCases[1] /* KeyValueMap[ConstantArray] /* Flatten, 
         rows]
Out[2]= {{1, 1, 1, 1}, {2, 2, 2, 2}, {3, 3, 3, 3}}
$\endgroup$
1
$\begingroup$

The odd element is necessarily the first or the last if the list were sorted, so either taking the second-smallest or second-largest element should work:

RankedMin[#, 2] & /@ data
RankedMax[#, 2] & /@ data

You could also take the median, though it would probably be slower.

This avoids the overhead of sorting each entire list or storing frequencies in a map (though I suppose it could be slow if your numbers are complex expressions that are hard to compare).

$\endgroup$
  • $\begingroup$ In each sublist, the second smallest (or second largest) is guaranteed not to be the odd one out. It shouldn't matter if the outlier is smaller in some lists and larger in others. $\endgroup$ – Sophie Alpert Nov 19 '15 at 7:47
  • $\begingroup$ Ah, ok, that's smart. :) But your approach is only returning one value for each sublist which is not exactly what OP wants. Maybe you can add a ConstantArray or something $\endgroup$ – Kuba Nov 19 '15 at 7:55
  • $\begingroup$ My mistake, thanks. $\endgroup$ – Sophie Alpert Nov 28 '15 at 1:51
0
$\begingroup$

Assuming that your statement was precisely what you need (remove n + 1 from the nth list), then this will work:

list = {{1, 1, 1, 1, 2}, {2, 2, 2, 2, 3}, {3, 3, 3, 4, 3};
MapIndexed[DeleteCases[#1, 1 + First@#2] &, list]
(* {{1, 1, 1, 1,}, {2, 2, 2, 2,}, {3, 3, 3, 3} *)

I suspect somehow that this isn't the general use case, however.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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