private static void NonzeroFilterGroup(int minValids, bool percentage, IMatrixData mdata, Parameters param,
                                               bool oneGroup, double threshold, double threshold2, FilteringMode filterMode, IList <string[]> groupCol
                                               )
        {
            List <int> valids    = new List <int>();
            List <int> notvalids = new List <int>();

            string[] groupVals = ArrayUtils.UniqueValuesPreserveOrder(groupCol);
            Array.Sort(groupVals);
            int[][] groupInds = CalcGroupInds(groupVals, groupCol);
            for (int i = 0; i < mdata.RowCount; i++)
            {
                int[] counts = new int[groupVals.Length];
                int[] totals = new int[groupVals.Length];
                for (int j = 0; j < groupInds.Length; j++)
                {
                    for (int k = 0; k < groupInds[j].Length; k++)
                    {
                        if (groupInds[j][k] >= 0)
                        {
                            totals[groupInds[j][k]]++;
                        }
                    }
                    if (PerseusPluginUtils.IsValid(mdata.Values.Get(i, j), threshold, threshold2, filterMode))
                    {
                        for (int k = 0; k < groupInds[j].Length; k++)
                        {
                            if (groupInds[j][k] >= 0)
                            {
                                counts[groupInds[j][k]]++;
                            }
                        }
                    }
                }
                bool[] groupValid = new bool[counts.Length];
                for (int j = 0; j < groupValid.Length; j++)
                {
                    groupValid[j] = PerseusPluginUtils.Valid(counts[j], minValids, percentage, totals[j]);
                }
                if (oneGroup ? ArrayUtils.Or(groupValid) : ArrayUtils.And(groupValid))
                {
                    valids.Add(i);
                }
                else
                {
                    notvalids.Add(i);
                }
            }
            PerseusPluginUtils.FilterRowsNew(mdata, param, valids.ToArray());
        }
        public void ProcessData(IMatrixData mdata, Parameters param, ref IMatrixData[] supplTables,
                                ref IDocumentData[] documents, ProcessInfo processInfo)
        {
            const bool rows      = true;
            int        minValids = PerseusPluginUtils.GetMinValids(param, out bool percentage);
            ParameterWithSubParams <int> modeParam = param.GetParamWithSubParams <int>("Mode");
            int modeInd = modeParam.Value;

            if (modeInd != 0 && mdata.CategoryRowNames.Count == 0)
            {
                processInfo.ErrString = "No grouping is defined.";
                return;
            }
            PerseusPluginUtils.ReadValuesShouldBeParams(param, out FilteringMode filterMode, out double threshold, out double threshold2);
            if (modeInd != 0)
            {
                int        gind     = modeParam.GetSubParameters().GetParam <int>("Grouping").Value;
                string[][] groupCol = mdata.GetCategoryRowAt(gind);
                if (param.GetParam <int>("Filter mode").Value == 2)
                {
                    //discarded
                    List <int> valids    = new List <int>();
                    List <int> notvalids = new List <int>();
                    string[]   groupVals = ArrayUtils.UniqueValuesPreserveOrder(groupCol);
                    Array.Sort(groupVals);
                    int[][] groupInds = CalcGroupInds(groupVals, groupCol);
                    for (int i = 0; i < mdata.RowCount; i++)
                    {
                        int[] counts = new int[groupVals.Length];
                        int[] totals = new int[groupVals.Length];
                        for (int j = 0; j < groupInds.Length; j++)
                        {
                            for (int k = 0; k < groupInds[j].Length; k++)
                            {
                                if (groupInds[j][k] >= 0)
                                {
                                    totals[groupInds[j][k]]++;
                                }
                            }
                            if (PerseusPluginUtils.IsValid(mdata.Values.Get(i, j), threshold, threshold2, filterMode))
                            {
                                for (int k = 0; k < groupInds[j].Length; k++)
                                {
                                    if (groupInds[j][k] >= 0)
                                    {
                                        counts[groupInds[j][k]]++;
                                    }
                                }
                            }
                        }
                        bool[] groupValid = new bool[counts.Length];
                        for (int j = 0; j < groupValid.Length; j++)
                        {
                            groupValid[j] = PerseusPluginUtils.Valid(counts[j], minValids, percentage, totals[j]);
                        }
                        if (modeInd == 2 ? ArrayUtils.Or(groupValid) : ArrayUtils.And(groupValid))
                        {
                            valids.Add(i);
                        }
                        else
                        {
                            notvalids.Add(i);
                        }
                    }
                    supplTables = new[] { PerseusPluginUtils.CreateSupplTabSplit(mdata, notvalids.ToArray()) };
                }
                NonzeroFilterGroup(minValids, percentage, mdata, param, modeInd == 2, threshold, threshold2, filterMode, groupCol);
            }
            else
            {
                if (param.GetParam <int>("Filter mode").Value == 2)
                {
                    supplTables = new[] { PerseusPluginUtils.NonzeroFilter1Split(rows, minValids, percentage, mdata, param, threshold, threshold2, filterMode) };
                }
                PerseusPluginUtils.NonzeroFilter1(rows, minValids, percentage, mdata, param, threshold, threshold2, filterMode);
            }
        }