简体   繁体   中英

seperate distict values from a list into different list object c#

I have a list object where I have 100 numbers. I want to separate all list object with respect to all unique numbers.

Here is my list object

public class USERDETAILS
{
     private long _ID;
     public long ID
     {
         get { return _ID; }
         set { _ID = value; }
     }

     private long _MSISDN;
     public long MSISDN
     {
         get { return _MSISDN; }
         set { _MSISDN = value; }
     }
}

List<USERDETAILS> lstUSERDETAILS = new List<USERDETAILS>();

I have 10 numbers in my list

ID  MSISDN
101 9000001
102 9000002
103 9000002
104 9000003
105 9000003
106 9000003
107 9000007
108 9000008
109 9000009
110 9000010

I want to get duplicated entries in different list objects. Here's expected output:

1st list object:

ID  MSISDN
101 9000001
102 9000002
104 9000003
107 9000007
108 9000008
109 9000009
110 9000010

2nd list object:

ID  MSISDN
103 9000002
105 9000003

3rd list object:

ID  MSISDN
106 9000003

I have tried with linq group by ;

var listOfUnique_USERDETAILS_Lists = listUSERDETAILS.GroupBy(p => p.MSISDN).Select(g => g.ToList());

Also I had tried iterating it over for loop to get distinct numbers and then putting up it in list<USERDETAILS> object and then creating it in new list of duplicated entries but want to do it with more simplified way.

Here you go.

If you run this:

List<UserDetails> source = new List<UserDetails>();

UserDetails[][] grouping = source
                         .GroupBy( x=> x.MSISDN )
                         .Select( y => y.OrderBy( z => z.ID ).ToArray() )
                         .ToArray()
                         ;

gives you an array of UserDetails[] .

grouping[n] gives you the array of all the UserDetails objects sharing the same MSISDN value, ordered by their ID property.

grouping[n][0] will give you the first such object for that MSISDN . Iterating over that will give you the "distinctified" set of "first" objects. Since every grouping is guaranteeed to have at least one such item, we can simply say:

UserDetails[] firstList = grouping.Select( x => x.First() ).ToArray() ;

You can get your 2nd, 3rd, 4th, etc. lists by:

        int n = 2 ; // specify a suitable value for n such that n > 0 (1:1st, 2:2nd, etc.)
        UserDetails[] nthList = grouping.Select( x => x.Skip(n-1).FirstOrDefault() ).Where( x => x != null ).ToArray() ;

Note: since the 2d array is jagged (and so, every MSISDN may not have an nth element, we use Skip(n-1).FirstOrDefault().Where( x => x != null ) to toss the missing items.

The more general solution would be to take the grouping[][] and *transpose its rows and columns, such that grouping[x][y] becomes ranking[y][x] . That lets you look at the transposed ranking[][] as having ranking[0] being the UserDetails[] that is your 1st-ranked objects across all MSISDN values, ranking[0] being your 2nd ranked objects across all MSISDN values, etc.

You you'll probably want to do something more than a simple transposition since any given MSISDN may not have an nth-ranked item, for any value of n larger than 0.

I believe (untested) that you can do the 2-D transposition something like this with LINQ:

UserDetails[][] ranking = Enumerable
                          .Range( 0 ,grouping.Max(x => x.Length) )
                          .Select( rank => Enumerable
                                           .Range(0,grouping.Length)
                                           .Select( msisdn => grouping[msisdn].Skip(rank-1).FirstOrDefault() )
                                           .Where( x => x != null )
                                           .ToArray()
                          )
                          .ToArray()
                          ;

At the end of which ranking[0] should be your first list, ranking[1] your second list and ranking[2] your third list.

So first group the items, using GroupBy , then you can iterate over the groups and project them out to IEnumerator objects, pulling out the groups that still have items left and yielding the next item, until none of the groups have any items.

//TODO give better name
public static IEnumerable<IEnumerable<T>> Foo<T, TKey>(
    IEnumerable<T> source, Func<T, TKey> selector)
{
    var groups = source.GroupBy(selector)
        .Select(group => group.GetEnumerator())
        .ToList();
    while (groups.Any())
    {
        yield return groups.Select(iterator => iterator.Current);
        groups = groups.Where(iterator => iterator.MoveNext())
            .ToList();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM