Один запрос для разных полей
От: peer  
Дата: 20.12.23 14:52
Оценка:
Есть такой код.
Для упрощения в классе 3 поля.
Суть в том что один запрос идет в foreach просто по разным полям.
Как можно схлопнуть это чтобы был один foreach?

using System.Linq.Expressions;

namespace helloworld
{
    class hello
    {
        static void Main()
        {
            var p1 = new Person() { Age = 3, Name = "vova" };
            var p2 = new Person() { Age = 3, Name = "vova2" };
            var p3 = new Person() { Age = 32, Name = "vova2" };
            var p4 = new Person() { Age = 33, Name = "vova2" };
            var p14 = new Person() { Age = 323, Name = "vova24" };

            var list = new List<Person>() { p1, p2, p3, p4, p14 };

            foreach (var p in list
                         .GroupBy(a => a.Id)
                         .Where(x => x.Select(a => a.Age)
                                 .Distinct()
                                 .Count() > 1
                         )
                         .SelectMany(s => s.Select(o => o)))
            {
                //log error by Age
            }
            
            foreach (var p in list
                         .GroupBy(a => a.Id)
                         .Where(x => x.Select(a => a.Name)
                                 .Distinct()
                                 .Count() > 1
                         )
                         .SelectMany(s => s.Select(o => o)))
            {
                //log error by Name
            }
        }

        class Person
        {
            public int Id;
            public string Name { get; set; }
            public int Age { get; set; }
        }
    }
}
Отредактировано 21.12.2023 0:08 IT . Предыдущая версия . Еще …
Отредактировано 21.12.2023 0:08 IT . Предыдущая версия .
Re: Один запрос для разных полей
От: Разраб  
Дата: 20.12.23 15:51
Оценка:
Здравствуйте, peer, Вы писали:

P>Есть такой код.

P>Для упрощения в классе 3 поля.
P>Суть в том что один запрос идет в foreach просто по разным полям.
P>Как можно схлопнуть это чтобы был один foreach?


чтш-нибудь типа Union
и потом еще раз distinct по id
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re: Один запрос для разных полей
От: 尿컙拋㕪⬎⤇Ǥ꧃푙刾ꄔ൒  
Дата: 20.12.23 18:06
Оценка: +1
никак. тебе надо найти айтемы, имеющие более одного неуникального значения по какому то из уникальных атрибутов, верно? код очень тяжело передает твои намерения. гораздо читабельнее было бы завести словарь Dictionary<string, object> и один раз пробежаться по коллекции с проверкой значений уникальных атрибитов по тому словарю попутно заполняя словарь. Обрати внимание на важность спртировки. Твой подход дискредиторует линк как технологию, кто то может посмотреть на это все ужаснуться и больше никогда к нему не прикасаться.

на быструю примерно так, добавил ref.

namespace HelloWorld
{
    class Hello
    {
        enum Attribute
        {
            Age, Name
        }

        static void Main()
        {
            var people = new List<Person>() {
                new () { Id = 1, Age = 3, Name = "vova" },
                new () { Id = 1, Age = 31, Name = "vova" },
                new () { Id = 2, Age = 32, Name = "vova2" },
                new () { Id = 2, Age = 33, Name = "vova2" },
                new () { Id = 4, Age = 323, Name = "vova24" },
                new () { Id = 4, Age = 323, Name = "vova25" }
            };

            List<(int, Attribute, object, object)> Validate(Person person, ref Dictionary<int, Dictionary<Attribute, object>> processedPeople)
            {
                object GetValue(Person person, Attribute attribute) =>
                   attribute switch
                   {
                       Attribute.Age => person.Age,
                       Attribute.Name => person.Name,
                       _ => throw new ArgumentException($"Invalid attribute: '{attribute}'"),
                   };

                var errors = new List<(int, Attribute, object, object)>();

                foreach (var attribute 
                    in Enum.GetValues<Attribute>())
                {
                    if (!processedPeople.TryGetValue(person.Id,
                        out var processedPerson))
                    {
                        processedPerson = new();
                        processedPeople.Add(person.Id, processedPerson);
                    }

                    if (!processedPerson.TryGetValue(attribute, out var originalValue))
                    {
                        originalValue = GetValue(person, attribute);
                        processedPerson.Add(attribute, originalValue);
                    }
                    else
                    {
                        var value = GetValue(person, attribute);
                        if (originalValue != value)
                        {
                            errors.Add(new(person.Id, attribute, value, originalValue));
                        }
                    }
                }

                return errors;
            }

            var processedPeople = new Dictionary<int, Dictionary<Attribute, object>>(); // note: mutable state
            foreach ((int id, Attribute attribute, object value, object originalValue) 
                in people.SelectMany(person => Validate(person, ref processedPeople)))
            {
                Console.WriteLine($"Person Id: {id} '{attribute}' value specified ambiguously, value: '{value}', original value: '{originalValue}'");
            }

            Console.ReadLine();
        }

        class Person
        {
            public int Id;
            public required string Name { get; set; }
            public int Age { get; set; }
        }
    }
}
Отредактировано 21.12.2023 11:20 尿컙拋㕪⬎⤇Ǥ꧃푙刾ꄔ൒ . Предыдущая версия . Еще …
Отредактировано 21.12.2023 11:15 尿컙拋㕪⬎⤇Ǥ꧃푙刾ꄔ൒ . Предыдущая версия .
Re: Один запрос для разных полей
От: Sinclair Россия https://github.com/evilguest/
Дата: 21.12.23 08:28
Оценка:
Здравствуйте, peer, Вы писали:

P>Как можно схлопнуть это чтобы был один foreach?

using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace helloworld
{
    class hello
    {
        static void Main()
        {
            var p1 = new Person() { Age = 3, Name = "vova" };
            var p2 = new Person() { Age = 3, Name = "vova2" };
            var p3 = new Person() { Age = 32, Name = "vova2" };
            var p4 = new Person() { Age = 33, Name = "vova2" };
            var p14 = new Person() { Age = 323, Name = "vova24" };

            var list = new List<Person>() { p1, p2, p3, p4, p14 };

            var g  = list.GroupBy(a => a.Id);
            var aa = g.Where(x => (x.Select(a => a.Age).Distinct().Count() > 1))
                       .SelectMany(s => s.Select(o => (id:o.Id, attr:"age")));
            var an = g.Where(x => (x.Select(a => a.Name).Distinct().Count() > 1))
                      .SelectMany(s => s.Select(o => (id:o.Id, attr:"name")));

            foreach (var e in aa.Union(an))
            {
                System.Console.WriteLine($"Group # {e.id} contains duplicates by {e.attr}");
            }
        }

        class Person
        {
            public int Id;
            public string Name { get; set; }
            public int Age { get; set; }
        }
    }
}

?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.