none
List - group by for index and select the worst status RRS feed

  • Question

  • Hello,

    I'm looking for a better solution, maybe with Groupby for the index.

    How can I filter out the worst status of an index?

    // ** Index, State HashSet<Tuple<string, bool>> hashsetResult; hashsetResult = new HashSet<Tuple<string, bool>>(); //State = 1 = bad //State = 0 = good

    Is one Index Bad, all others positions are bad. foreach (var item in AllPositions) { var posIncluded = hashsetResult.Where(r => r.Item1 == item.Index).FirstOrDefault(); if (posIncluded == null) { hashsetResult.Add(new Tuple<string, bool>(item.Index, item.State)); } else { if (posIncluded.Item2 == false) is not bad { if (item.State == true) // is bad { hashsetResult.Remove(posIncluded); hashsetResult.Add(new Tuple<string, bool>(item.Index, item.State)); } } } Pos;Index;State; Index;State 1;1;1;;-------------1;1 2;1;1;;-------------2;1 3;1;0;;-------------3;1 4;2;1;;-------------4;1 5;2;1;;-------------5;0 6;3;1;;-------------6;1 7;3;0;;; 8;3;1;;; 9;3;1;;; 10;4;1;;; 11;4;1;;; 12;4;1;;; 13;5;0;;; 14;6;1;;;


    Thanks for tips in advance.

    Best regards Markus


    Wednesday, December 18, 2019 6:30 PM

Answers

  • Yes basically.  The "GroupBy" function is a little complicated to understand.  It's complicated enough in SQL, but doing it in Linq is even trickier.  The first function returns the "key" that the function will group by.  It rearranges all the records into groups that have the same key value.  Then, for all the records in a group, it calls that second function to return a group value.  The parameters to the third function, then, are the "key" value, and the list of all of the group results.


    Tim Roberts | Driver MVP Emeritus | Providenza &amp; Boekelheide, Inc.

    • Marked as answer by Markus Freitag Wednesday, January 1, 2020 11:13 AM
    Wednesday, January 1, 2020 7:39 AM

All replies

  • Do you mean

        var summary = hashResults.GroupBy( r => r.Index, r => r.State,
            (idx, states) => new { Index=idx, Worst=states.Min() } );
        foreach( var result in summary )
        {
            Console.WriteLine( result.Index, result.Worst );
        }



    Tim Roberts | Driver MVP Emeritus | Providenza &amp; Boekelheide, Inc.

    Thursday, December 19, 2019 7:23 AM
  • Hi Markus,

    Thank you for posting here.

    For this thread, I have some questions and want to confirm.

    1. Although you gave us an example, I still don't quite understand your grouping rules.

    2. What does AllPositions look like?

    Could you please describe your problem in more detail and give us more information?

    Looking forward to your reply.

    Best Regards,

    Timon


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, December 19, 2019 7:35 AM
  • Do you mean


    Hello Tim,

    Yes, I have a list with 14 positions, these are grouped by index.
    The result should now be the lower list.
    For each index I have a list again and have to log the minimum.
    Tim Roberts recognized it and published a solution. Thank you.
    I wouldn't have come up with the solution. @Tim, how was your approach?

    -1 = bad, 0 = good,  1 = bad   --> but we need in the result only 0 or 1.

    var summary = AllPositions.GroupBy(r => r.Index,  // ***AA
       r => r.State,                                  // ***BB
       (idx, states) => new { Index = idx, Worst = states.Min() }); // ***CC
    foreach (var result in summary)
    {
    	Console.WriteLine(result.Index, result.Worst);
    }
    Can you explain it?
    // ***AA means the requested group.
    // ***BB means the result, the state of the group
    // ***CC like a filter, ids input parameter, states return value

    3 sample

    states is the list and here we need one row.
    In order to understand the procedure I have implemented another criterion.
    State01 and State02. The whole group is bad if a state of a board has the value 1.
    How can I solve it with LinQ? (see picture below)
    @Tim, Can you help me again for more as one condition.
    Thanks for tips in advance.
    Second:
      For the state I use an enum, can I implement an extension? If yes, how is the best way?
    public enum PosState
    {
    	Good = 3,
    	GoodLevel75 = 2,
    	GoodLevel50 = 1,
    	Bad = 0,
    	Invalid = -1
    }
    
    var summary = AllPositions.GroupBy(r => r.Index,
    				   r => r.State,
     (idx, states) => new { Index = idx, Worst = states.Min(), BoardState = (states.Min() == PosState.Good) ? 0 : 1 });
    
    foreach (var result in summary)
    {             
    	Log.Debug($"Index= {result.Index}, result - the worst = {result.Worst}   boardState = {result.BoardState}");
    }
    string goodbadListIndex = string.Join("", summary.Select(x => x.BoardState.ToString()).ToArray());

          Example 11000      Board 1 is bad, 2 is bad, 3 is good, 4 is good, 5 is good
         
    @Timon, you understood my problem?

    With best regards Markus

    map new

    Thursday, December 19, 2019 6:08 PM
  • Hi Markus,

    Thanks for your feedback.

    You said: Is one Index Bad, all others positions are bad, so I think we should use state.Max() instead of state.Min() in linq.

    And if state is a list, you can refer to the following code.

               var States = from row in AllPositions
                            select new
                            {
                                Index = row.Index,
                                State = row.State.Max()
                            };
                var result = from row in States
                             group row by row.Index into g
                             select new
                             {
                                 Index = g.Key,
                                 State = g.Max(x=>x.State)
                             };
    
    
                foreach (var item in result)
                {
                    Console.WriteLine(item.Index+" "+item.State);
                }

    If you want to use enum values to compare with int values, you can do it like this.

    (PosState)3 == PosState.Good

    Hope this could be helpful.

    Best Regards,

    Timon


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.


    Friday, December 20, 2019 8:05 AM
  • Try run,type: appwiz.cpl in add/remove open windows services (L.sub menu) scroll to and check Indexing close out restart pc.Once set,you can manipulate indexing thru control panel/indexing.Also,use Microsoft/TechNet indexing catalog,you might should get the script to help.

    https://gallery.technet.microsoft.com/scriptcenter

    Saturday, December 21, 2019 3:53 AM
  • Hope this could be helpful.

    Hello!

    Maybe can you make or give a short example. Is that possible? Can you please answer yes or no? Or someone who knows.

       Thanks in advance.

    So I need 2 queries. Is it not possible to make one query, right?

    But if a position is not processed, however, the state is bad

    I need an enum to differentiate the status for another analysis.

    So I think Tim was right about Min. I mean I have to group first. Is not easy.

    Greetings Markus

    public enum PosState
    {
    	Good = 3,
    	GoodLevel75 = 2,
    	GoodLevel50 = 1,
    	Bad = 0,
    	Invalid = -1
    }

    Monday, December 30, 2019 11:35 AM
  • To produce the results in the right side of your spreadsheet, the answer is easy.  Instead of grouping on r.State, just group on r.State01+r.State02.  Since a board fails unless ALL of its tests pass, you want Max, not Min.

    using System;
    using System.Linq;
    using System.Xml.Linq;
    using System.Collections.Generic;
    
    struct Position
    {
        public int Pos;
        public int Index;
        public int State01;
        public int State02;
        public Position( int a, int b, int c, int d )
        {
            Pos = a;
            Index = b;
            State01 = c;
            State02 = d;
        }
    }
    
    class Program
    {
        static List<Position> Make()
        {
            List<Position> dataset = new List<Position>();
            dataset.Add( new Position(1,1,0,1) );
            dataset.Add( new Position(2,1,0,0) );
            dataset.Add( new Position(3,1,0,1) );
            dataset.Add( new Position(4,2,0,0) );
            dataset.Add( new Position(5,2,0,0) );
            dataset.Add( new Position(6,3,1,0) );
            dataset.Add( new Position(7,3,0,0) );
            dataset.Add( new Position(8,3,1,0) );
            dataset.Add( new Position(9,3,1,0) );
            dataset.Add( new Position(10,4,1,1) );
            dataset.Add( new Position(11,4,1,1) );
            dataset.Add( new Position(12,4,1,1) );
            dataset.Add( new Position(13,5,0,0) );
            dataset.Add( new Position(14,6,1,1) );
            return dataset;
        }
    
        static public void Main(string[] args)
        {
            List<Position> dataset = Make();
            var summary = dataset.GroupBy(
                r => r.Index,
                r => r.State01+r.State02,
                (idx,states) => new{ Index=idx, Worst=states.Max() }
            );
    
            foreach( var row in summary )
            {
                Console.WriteLine( "{0} {1}", row.Index, row.Worst );
            }
        }
    }
    

    This produces

    C:\tmp>x
    1 1     
    2 0     
    3 1     
    4 2     
    5 0     
    6 2     
            
    C:\tmp> 

    To implement the enum as you have it in your example, you are going to need to use code in a loop instead of Linq, because Linq doesn't have any idea what "GoodLevel75" and "GoodLevel50" mean.

    Note that there is NOTHING WRONG with doing this kind of thing in a loop.  Linq can be fun, but unless you are actually working with a remote database server, it's hard to see any real benefit, especially if it makes the code harder to understand.


    Tim Roberts | Driver MVP Emeritus | Providenza &amp; Boekelheide, Inc.

    Monday, December 30, 2019 8:41 PM
  • Hello Tim,

    Thanks a lot of your sample. Great.

    Have a good new year 2020!

    Last Question, syntax

     var summary = dataset.GroupBy(
                r => r.Index,
                r => r.State01+r.State02,
                (idx,states) => new{ Index=idx, Worst=states.Max() }
            );

    If I have here two variables

    r => r.Index,
    r => r.State01+r.State02

    I need here also two inputs, right?

    (idx,states)

    Greetings Markus

    Tuesday, December 31, 2019 11:20 AM
  • Yes basically.  The "GroupBy" function is a little complicated to understand.  It's complicated enough in SQL, but doing it in Linq is even trickier.  The first function returns the "key" that the function will group by.  It rearranges all the records into groups that have the same key value.  Then, for all the records in a group, it calls that second function to return a group value.  The parameters to the third function, then, are the "key" value, and the list of all of the group results.


    Tim Roberts | Driver MVP Emeritus | Providenza &amp; Boekelheide, Inc.

    • Marked as answer by Markus Freitag Wednesday, January 1, 2020 11:13 AM
    Wednesday, January 1, 2020 7:39 AM