Есть ли способ получить все возможные комбинации в 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 еще один.
Вы уверены, что группировка — это то, что вам нужно, или вы просто хотите запросить объект, чтобы найти или исключить определенные объекты? Группировка - это другое.
@ScottHannen Да, я хочу получить только поля со значением, отличным от «0», но если у элемента есть одно свойство со значением «0», я хочу получить другие свойства, имеет смысл? и получить все возможные комбинации из всей коллекции, будет более 90к записей
Я согласен с @EdPlunkett. Если бы у вас был список, то код был бы Where(c => c.MyList.All(x => x != "0"))
Можете ли вы ПОВОРОТИТЬ свой стол? Это делает такие запросы намного проще
Если вы исключите одно значение, потому что оно равно «0» или пусто, как вы узнаете, какое из них было исключено? Вы просто хотите извлечь список строк из каждого объекта, и не имеет значения, одна это строка или восемь? Возможно, было бы понятнее, если бы вы показали, как будут выглядеть данные после их извлечения.
@ScottHannen Я отредактировал свой вопрос, чтобы попытаться быть более конкретным.
Можете ли вы добавить некоторые образцы данных и ожидаемый результат. После редактирования не уверен, что мой ответ работает.
@JuanCarlosOropeza Готово, спасибо!
Сначала вы упоминаете какой-то фильтр, теперь вы упоминаете, что нужна группа, основанная только на структуре? Тем не менее, я хочу увидеть, какой результат вы хотите, я не хочу догадываться, поскольку похоже, что я уже догадываюсь неправильно. Мой ответ направлен на то, чтобы найти строки с нужной вам структурой. Но это кажется совершенно другим
@JuanCarlosOropeza Извините, английский, это не мой естественный язык. Иногда я склонен писать немного запутанно, в основном, у меня есть коллекция со структурой, подобной последнему редактированию, я хочу иметь возможность сгруппировать свою коллекцию, как я упоминал выше, Row1... RowN это только для того, чтобы показать, в коллекции нет таких полей, как Row1 и т. д. Для того, чтобы получить одну «группу» элементов и собрать ее вместе в рамках одного запроса в SQL, затем еще одну «группу» и запустить ее в SQL , я не знаю, есть ли в этом смысл?
Есть шанс, что ваш основной язык испанский? Я знаю, что строка # - это просто обработчик. Но у вас должен быть какой-то идентификатор, который будет первичным ключом. Что я понимаю под группами. Вы хотите добавить новое поле и начать нумерацию от 1 до номера отдельной группы? И группа основана на том, сколько свойств с 0 имеет?
Если я не ошибаюсь, вам нужно сгенерировать перестановка, где строка счетчика — н!. Посмотрите на этот ответ: stackoverflow.com/questions/3621494/…
@JuanCarlosOropeza Да, это испанский, есть ли шансы попытаться связаться с вами по сообщению?





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
Вы можете использовать отражение, чтобы получить все свойства с именем 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).
Если это правильные имена свойств, рассматривали ли вы возможность использования
List<String>вместо дискретных полей?