1
class Program
{
    static void Main(string[] args)
    {

        int[] arr1 = { 1, 2, 3, 4 };
        int[] arr2 = { 1, 2, 3 };
        int[] arr3 = { 1, 2, 3 };
        int[] arr4 = { 1, 2, 3, 4 };
        int[] arr5 = { 1, 2, 3, 4 };
        int[] arr6 = { 1, 2, 3, 4, 5 };

        Order Order1 = new Order { OrderId = 1, Deatils = arr1 };
        Order Order2 = new Order { OrderId = 2, Deatils = arr2 };
        Order Order3 = new Order { OrderId = 3, Deatils = arr3 };
        Order Order4 = new Order { OrderId = 4, Deatils = arr4 };
        Order Order5 = new Order { OrderId = 5, Deatils = arr5 };
        Order Order6 = new Order { OrderId = 6, Deatils = arr6 };

        // I want to Output like this based on same values in details object.
        string similarOrderDetailsOrderIds_1 = "1,4,5";
        string similarOrderDetailsOrderIds_2 = "2,3";
        string similarOrderDetailsOrderIds_3 = "5";

    }
}

public class Order
{
    public int OrderId { get; set; }
    public int[] Deatils { get; set; }

}

I want to output like this because OrderId-1,4,5 have the same values in Details.

string similarOrderDetailsOrderIds_1 = "1,4,5";

string similarOrderDetailsOrderIds_2 = "2,3";

string similarOrderDetailsOrderIds_3 = "5";

user547534
  • 70
  • 8

2 Answers2

0

This extension method is a generic generalization of the solution provided by Michael Liu here which orders elements prior to hash code generation and will work for any T which itself correctly implements GetHashCode() and Equals():

static class Extensions
{
    public static int GetCollectionHashCode<T>(this IEnumerable<T> e)
    {
        return ((IStructuralEquatable)e.OrderByDescending(x => x).ToArray())
            .GetHashCode(EqualityComparer<T>.Default);
    }
}

You can utilize it like so:

var orders = new[] { Order1, Order2, Order3, Order4, Order5, Order6 };

var groups = orders
    .Where(x => x.Deatils != null)
    .GroupBy(x => x.Deatils.GetCollectionHashCode())
    .Select(x => x.Select(y => y.OrderId));

Note: Deatils typo above is intentional as per OP.

Creyke
  • 1,887
  • 2
  • 12
  • 16
  • Thanks @Creyke for your answer. it look like depends on element order also, suppose if I change the order for arr3 = { 1, 3, 2 }; elements like this then result set is different – user547534 Aug 06 '21 at 11:33
  • Element order is handled by `e.OrderByDescending(x => x)` so all enumerables are ordered prior to hashing. – Creyke Aug 06 '21 at 11:34
  • Hi @Creyke how to handle the null value in this query suppose int[] arr6 = null; then it throws error how to handle this – user547534 Aug 07 '21 at 08:19
  • Use a `Where()` method. Have updated answer to reflect. More information here: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.where – Creyke Aug 07 '21 at 09:50
0

You could use LINQ as the other answer provided or create a helper method to group them for you.

public static IEnumerable<IEnumerable<T>> Aggregate<T>(IEnumerable<T> ungrouped, Func<T, T, bool> Expression)
{
    // create a place to put the result
    List<List<T>> groupedItems = new();

    // create a mutable storage to keep track which ones we shouldn't compare 
    List<T> mutableBag = ungrouped.ToArray().ToList();

    // n^2 isn't great but it was easy to implement, consider creating a hash from all elements and use those instead of manual comparisons
    foreach (var left in ungrouped)
    {
        // create a place to store any similar items
        List<T> similarItems = new();

        // compare element to every remaining element, if they are similar add the other to the similar list
        foreach (var right in mutableBag)
        {
            if (Expression(left, right))
            {
                similarItems.Add(right);
            }
        }

        // if we didn't find any similar items continue and let GC collect similar items
        if (similarItems.Count == 0)
        {
            continue;
        }

        // since we found items remove the from the mutable bag so we don't have duplicate entries
        foreach (var item in similarItems)
        {
            mutableBag.Remove(item);
        }

        // add the similar items to the result
        groupedItems.Add(similarItems);
    }

    return groupedItems;
}
public static bool Compare<T>(T[] Left, T[] Right)
{
    // this compare method could be anything I would advise against doing member comparison like this, this is simplified to provide how to use the Aggregate method and what the CompareMethod might look like for comlpex types
    if (Left.Length != Right.Length)
    {
        return false;
    }

    foreach (var item in Left)
    {
        if (Right.Contains(item) is false)
        {
            return false;
        }
    }

    return true;
}

For the given example

Order Order1 = new Order { OrderId = 1, Deatils = arr1 };
Order Order2 = new Order { OrderId = 2, Deatils = arr2 };
Order Order3 = new Order { OrderId = 3, Deatils = arr3 };
Order Order4 = new Order { OrderId = 4, Deatils = arr4 };
Order Order5 = new Order { OrderId = 5, Deatils = arr5 };
Order Order6 = new Order { OrderId = 6, Deatils = arr6 };

Order[] arrs = { Order1, Order2, Order3, Order4, Order5, Order6 };

We could use this new helper method like this:

var groupedItems = Aggregate(arrs, (left, right) => Compare(left.Deatils, right.Deatils));
DekuDesu
  • 2,224
  • 1
  • 5
  • 19