Как сгруппировать в LINQ, используя несколько критериев?

Есть ли способ получить все возможные комбинации в ObservableCollection?

У меня есть такая модель:

    public string MyProperty { get; set; }
    public string MyProperty2 { get; set; }
    public string MyProperty3 { get; set; }
    public string MyProperty4 { get; set; }
    public string MyProperty5 { get; set; }
    public string MyProperty6 { get; set; }
    public string MyProperty7 { get; set; }
    public string MyProperty8 { get; set; }

И я заполняю эту модель данными из электронной таблицы, но некоторые значения имеют нулевые или пустые значения (которые мне нужно исключить). Есть ли способ получить все возможные комбинации с одним и тем же шаблоном?

Например, все комбинации со значениями, отличными от 0 во всех свойствах, и все комбинации, когда есть только одно свойство со значением, а остальные нулевые и т.д.

Пока у меня что-то вроде этого:

var group1 = _sourceStructure.Where(c => c.MyProperty != "0" && c.MyProperty2 != "0" && c.MyProperty3 != "0" && c.MyProperty4 != "0"
        && c.MyProperty5 != "0" && c.MyProperty6 != "0" && c.MyProperty7 != "0" && c.MyProperty8 != "0");

Но при этом мне нужно использовать более 30 случаев, чтобы оценить, есть ли способ получить все возможные комбинации с помощью LINQ или другого решения?

Я хочу построить SQL-запрос со значениями из коллекции, но если значение равно 0 или пусто, я не буду добавлять это значение в запрос. Я хочу получить все комбинации с одним и тем же шаблоном, чтобы иметь возможность помещать все элементы с одним и тем же шаблоном в IN в SQL.

Выходные данные будут примерно такими:

string query = @"Select field1, field2, field3, fieldn FROM table WHERE "

query = query + "field1 = " + _sourceStructure.MyProperty1;

query = query + "fieldN =  " + _sourceStructure.MyPropertyN;

В принципе, мне все равно, какое значение. Мне нужно только сгруппировать коллекцию со всеми возможными комбинациями с одним и тем же шаблоном.

Пример данных из исходного файла в Excel:

       MyProperty1 MyPropert2 MyPropertN
Row1      0          1           3
Row2      2          0           6
Row3      0          5           9
Row4      9          9           4
Row5      4          3           6
Row6      0          0           0

Вот, например, я ожидаю, что Row1 и Row3 будут в одной группе (значения не совпадают, но "структура" одинаковая), и тогда Row4 и Row5 будут другой группой, Row6 другой, и Row2 еще один.

Если это правильные имена свойств, рассматривали ли вы возможность использования List<String> вместо дискретных полей?

15ee8f99-57ff-4f92-890c-b56153 07.05.2019 22:29

Вы уверены, что группировка — это то, что вам нужно, или вы просто хотите запросить объект, чтобы найти или исключить определенные объекты? Группировка - это другое.

Scott Hannen 07.05.2019 22:32

@ScottHannen Да, я хочу получить только поля со значением, отличным от «0», но если у элемента есть одно свойство со значением «0», я хочу получить другие свойства, имеет смысл? и получить все возможные комбинации из всей коллекции, будет более 90к записей

Shepniel Sh 07.05.2019 22:33

Я согласен с @EdPlunkett. Если бы у вас был список, то код был бы Where(c => c.MyList.All(x => x != "0"))

juharr 07.05.2019 22:34

Можете ли вы ПОВОРОТИТЬ свой стол? Это делает такие запросы намного проще

Juan Carlos Oropeza 07.05.2019 22:34

Если вы исключите одно значение, потому что оно равно «0» или пусто, как вы узнаете, какое из них было исключено? Вы просто хотите извлечь список строк из каждого объекта, и не имеет значения, одна это строка или восемь? Возможно, было бы понятнее, если бы вы показали, как будут выглядеть данные после их извлечения.

Scott Hannen 07.05.2019 22:36

@ScottHannen Я отредактировал свой вопрос, чтобы попытаться быть более конкретным.

Shepniel Sh 07.05.2019 22:56

Можете ли вы добавить некоторые образцы данных и ожидаемый результат. После редактирования не уверен, что мой ответ работает.

Juan Carlos Oropeza 07.05.2019 22:58

@JuanCarlosOropeza Готово, спасибо!

Shepniel Sh 07.05.2019 23:09

Сначала вы упоминаете какой-то фильтр, теперь вы упоминаете, что нужна группа, основанная только на структуре? Тем не менее, я хочу увидеть, какой результат вы хотите, я не хочу догадываться, поскольку похоже, что я уже догадываюсь неправильно. Мой ответ направлен на то, чтобы найти строки с нужной вам структурой. Но это кажется совершенно другим

Juan Carlos Oropeza 07.05.2019 23:16

@JuanCarlosOropeza Извините, английский, это не мой естественный язык. Иногда я склонен писать немного запутанно, в основном, у меня есть коллекция со структурой, подобной последнему редактированию, я хочу иметь возможность сгруппировать свою коллекцию, как я упоминал выше, Row1... RowN это только для того, чтобы показать, в коллекции нет таких полей, как Row1 и т. д. Для того, чтобы получить одну «группу» элементов и собрать ее вместе в рамках одного запроса в SQL, затем еще одну «группу» и запустить ее в SQL , я не знаю, есть ли в этом смысл?

Shepniel Sh 07.05.2019 23:24

Есть шанс, что ваш основной язык испанский? Я знаю, что строка # - это просто обработчик. Но у вас должен быть какой-то идентификатор, который будет первичным ключом. Что я понимаю под группами. Вы хотите добавить новое поле и начать нумерацию от 1 до номера отдельной группы? И группа основана на том, сколько свойств с 0 имеет?

Juan Carlos Oropeza 07.05.2019 23:31

Если я не ошибаюсь, вам нужно сгенерировать перестановка, где строка счетчика — н!. Посмотрите на этот ответ: stackoverflow.com/questions/3621494/…

vladimir 07.05.2019 23:32

@JuanCarlosOropeza Да, это испанский, есть ли шансы попытаться связаться с вами по сообщению?

Shepniel Sh 07.05.2019 23:33
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
14
89
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

UNPIVOT ваша таблица примерно так:

 Observable     Property      Value
     A             1            0
     A             2            1
     A             3            2
     B             1            0
     B             2            0
     B             3            1
     C             1            1
     C             2            2
     C             3            3

Все комбинации со значениями, отличными от 0, во всех свойствах:

SELECT Observable
FROM Table
GROUP BY Observable
HAVING SUM(CASE WHEN VALUE = 0 THEN 1 ELSE 0 END) = 0

Все комбинации, когда есть только одно свойство со значением, а остальные нулевые:

SELECT Observable
FROM Table
GROUP BY Observable
HAVING COUNT(CASE WHEN VALUE > 0 THEN 1 END) = 1

ДЕМО SQL

Ответ принят как подходящий

Вы можете использовать отражение, чтобы получить все свойства с именем MyPropertyn, где n равно 1 любому, а затем вы можете использовать List из PropertyInfos, чтобы вычислить битовую маску для заполненных свойств и сгруппировать по этому значению.

Сначала некоторые методы расширения, которые я использую:

public static class StringExt {
    public static string Past(this string s, string starter) {
        var starterPos = s.IndexOf(starter);
        return starterPos == -1 ? String.Empty : s.Substring(starterPos + starter.Length);
    }
}

public static class NumericExt {
    public static int ToInt<T>(this T obj) => Convert.ToInt32(obj);

    public static int IntPow(this int x, int pow) {
        int ans = 1;

        while (pow != 0) {
            if ((pow & 0x1) == 1)
                ans *= x;
            x *= x;
            pow >>= 1;
        }
        return ans;
    }
}

Теперь вы можете собрать интересующие свойства, отсортировать, а затем вычислить битовую маску для каждой строки:

var myPropInfos = typeof(COC).GetProperties()
                             .Where(pi => pi.Name.StartsWith("MyProperty"))
                             .OrderBy(pi => pi.Name.Past("MyProperty").ToInt()) // just in case properties aren't ordered
                             .ToList();
var GroupedFilters = src.Select(r => new { r, ValuedMask = myPropInfos.Select((pi, p) => pi.GetValue(r).ToString() != "0" ? 2.IntPow(p) : 0).Sum() })
                        .GroupBy(rm => rm.ValuedMask, rm => rm.r);

Если первое свойство не заканчивается целым числом, вам понадобится тест для обработки этого в порядке или, альтернативно, (особенно если свойства не заканчиваются числом), вы можете не использовать OrderBy и использовать любой порядок GetProperties возвращается - порядок не имеет значения. Возвращенный ответ представляет собой IGrouping для каждой комбинации оцененных свойств, а Key битовая маска, показывающая, какие свойства были оценены.

Если у вас более 31 свойства, вам следует переключиться на использование long и создать очевидный метод расширения LongPow (2L.LongPow(p) : 0L).

Другие вопросы по теме