我已經看到以不同的方式提出這個問題(檢查列??表是否包含某個字串或字串是否包含任何給定的字符),但我需要別的東西。
我正在開發的程式與撲克相關,并在多個 DataGridViews 中以 [rank][suit] 格式顯示撲克牌串列,例如 AhKd5h3c。
現在,我有這個基本的文本框過濾器,它作業正常。
for (int i = 0; i < allFilteredRows.Count; i )
{
allFilteredRows[i] = new BindingList<CSVModel>(allRows[i].Where
(x => x.Combo.Contains(txtHandFilter.Text)).ToList());
}
allFilteredRows是我的 DataGridViews 的資料源。allRows是來自 SQL 資料庫的未經過濾的手牌串列。Combo是個人撲克牌。
不過,這只過濾文本框中的確切字符序列。我想要的是過濾每個等級并單獨適合。因此,如果用戶鍵入“AK”,則應顯示包含(至少)一張 A 和一張 K 的所有組合。如果輸入是'sss',它應該過濾所有至少有三張黑桃的牌。字符的順序應該無關緊要('KA' 等于 'AK'),但需要包含每個字符,并且可以組合等級和花色,例如 AKh 應該過濾所有至少有一張 A 的手牌和國王心。
這超出了我對 LINQ 的了解,因此我將不勝感激。
uj5u.com熱心網友回復:
在我看來,您需要執行兩個拆分操作。首先,您需要拆分過濾器string,使其包含其中的單個卡片過濾器 - 等級、花色或特定卡片。您可以使用正則運算式執行此操作。
首先,創建代表可能的等級和可能的套裝的字符集:
var ranks = "[23456789TJQKA]";
var suits = "[hsdc]";
然后,創建一個正則運算式來提取各個卡片過濾器:
var aCardFilter = $"{ranks}{suits}";
最后,使用從正則運算式(或行內它)回傳匹配值的擴展方法,您可以拆分過濾器,然后將相似的過濾器分組。您最終會得到兩個過濾器,單獨的卡片過濾器和等級/套件過濾器:
var cardFilters = txtHandFilter.Text.Matches(aCardFilter).ToList();
var suitRankFilters = txtHandFilter.Text.GroupBy(filterCh => filterCh).ToList();
現在您需要將手string分成一組卡片。由于每張卡片都是兩個字符,因此您可以在每第二個位置拆分子字串。我把它包裝在一個本地函式中以使代碼更清晰:
IEnumerable<string> handToCards(string hand) => Enumerable.Range(0, hand.Length / 2).Select(p => hand.Substring(2 * p, 2));
現在,您可以通過檢查每張牌是否出現在手牌中來測驗一手牌是否匹配卡片過濾器,并通過檢查每張牌在手牌中的出現頻率是否至少與過濾器中的一樣頻繁來匹配套件/等級過濾器:
bool handMatchesCardFilters(string hand, List<string> filters)
=> filters.All(filter => handToCards(hand).Contains(filter));
bool handMatchesFilters(string hand, List<IGrouping<char, char>> filters)
=> filters.All(fg => handToCards(hand).Count(card => card.Contains(fg.Key)) >= fg.Count());
最后,您已準備好過濾行:
for (int i = 0; i < allFilteredRows.Count; i)
allFilteredRows[i] = new BindingList<CSVModel>(
allRows[i].Where(row => handMatchesCardFilters(row.Combo, cardFilters) &&
handMatchesFilters(row.Combo, suitRankFilters))
.ToList());
需要的擴展方法是
public static class StringExt {
public static IEnumerable<string> Matches(this string s, string sre) => Regex.Matches(s, sre).Cast<Match>().Select(m => m.Value);
}
uj5u.com熱心網友回復:
將您的過濾器字串轉換為卡片串列(從我看來,如果第二個字符很小,則每個專案的長度為 2,否則長度為 1)。
使用 GroupBy 獲取每張卡片的數量,因此您應該使用 struct { "K", 3 } 而不是 "KKK"。 https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.groupby?view=net-5.0
重復每只手(我假設,每只手都是 List 而不僅僅是“AhKd5h3c”字串)
手動迭代檢查它是否包含來自 p2 輸出的所有專案(我假設 { "K", 3 } 也應該回傳具有 4 "K" 的組合:
public bool Match(object GroupedCombo, object filter) { foreach (var item in filter) { if (!GroupedCombo.Contains(x => x.Card==filter.Card && x.Count>=filter.Count)) return false; } return true; }
uj5u.com熱心網友回復:
聽起來您想評估過濾器的多個條件......
您需要評估的條件看起來像是需要您決議一個字串并推斷出卡片組合的表示。這里的問題是它沒有任何分隔符。
對于我的建議,您將需要它們:
for (int i = 0; i < allFilteredRows.Count; i )
{
allFilteredRows[i] = new BindingList<CSVModel>(allRows[i].Where
(x => txtHandFilter.Text.Split(" ").All(y => x.Combo.Contains(y)).ToList());
}
它是文本框,您應該將卡片組合用空格分隔。
如果您愿意,您可以找到其他一些方法來分隔 txtHandFilter,但我認為這可以回答您的基本問題。
編輯:我只能想到兩個選項來從您想要的文本框中提出字串陣列:
1:定界。
2:逐字符決議它以從字典中找到匹配卡片型別表示的字串。(對我來說這似乎更不切實際)
至于如何計算出現次數,我認為 Micha? Wolinski 的想法是正確的。
using System;
using System.Linq;
var cards = from card in txtHandFilter.Text.Split(" ")
group card by card
into g
select new { Card = g.Key, Count = g.Count() };
for (int i = 0; i < allFilteredRows.Count; i )
{
allFilteredRows[i] = new BindingList<CSVModel>(allRows[i]
.Where(x => cards
.All(y => x.Combo.Contains(String.Concat(Enumerable.Repeat(y.Card, y.Count)))
.ToList());
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/318211.html
上一篇:我想使用Linq修改物件中的資料
