次のコレクションを検討してください。
- 真実
- 間違い
- 間違い
- 間違い
- 真実
- 真実
- 間違い
- 間違い
構造化された方法で表示したい、たとえばTreeView
. グループ全体などに境界線を引きたいと思っています。
- 真のグループ
- 真実
- 偽グループ
- 間違い
- 間違い
- 間違い
- 真のグループ
- 真実
- 真実
- 偽グループ
- 間違い
- 間違い
できるだけ少ない手続き型コードでこれを達成するにはどうすればよいですか?
次のコレクションを検討してください。
構造化された方法で表示したい、たとえばTreeView
. グループ全体などに境界線を引きたいと思っています。
できるだけ少ない手続き型コードでこれを達成するにはどうすればよいですか?
これはあなたが探していることを行い、一般的です:
private static IEnumerable<IGrouping<int, T>> GroupConsecutive<T>(this IEnumerable<T> set, Func<T, T, bool> predicate)
{
var i = 0;
var k = 0;
var ranges = from e in set
let idx = ++i
let next = set.ElementAtOrDefault(idx)
let key = (predicate(e, next)) ? k : k++
group e by key into g
select g;
return ranges;
}
使用法:
var set = new List<bool>
{
true,
false,
false,
false,
true,
true,
false,
false,
};
var groups = set.GroupConsecutive((b1, b2) => (b1 == b2));
foreach (var g in groups)
{
Console.WriteLine(g.Key);
foreach (var b in g)
Console.WriteLine("\t{0}", b);
}
出力:
0
True
1
False
False
False
2
True
True
3
False
False
受け入れられた回答のコードは元の質問のニーズを満たしていますが、より複雑なオブジェクトの IEnumerables を処理するときにフォールオーバーします (列挙型の最後の項目を「次の」項目と比較するときに、述語が例外をスローする傾向があるため) [定義により、常に null になります])。
このバージョンは、より複雑なオブジェクトを処理します:
public static IEnumerable<IGrouping<int, T>> GroupConsecutive<T>(this IEnumerable<T> set, Func<T, T, bool> predicate)
{
var i = 0;
var k = 0;
var ranges = from e in set
let idx = ++i
let next = set.ElementAtOrDefault(idx)
let key = next == null ? k : (predicate(e, next)) ? k : k++
group e by key into g
select g;
return ranges;
}
Delay のブログ( http://blogs.msdn.com/delay/archive/2009/09/23/if-it-walks-like-a-duck-and-talks-like- ) の疑似TreeGridをチェックしてみてください。 a-duck-it-must-be-a-treegrid-a-simple-xaml-only-treegrid-ui-for-wpf.aspx
(ソース: msdn.com )
public class GroupConsecutiveEqualItemsConverter : IValueConverter
{
static readonly object UnsetValue = new object();
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
IEnumerable source = value as IEnumerable;
if (source == null) return DependencyProperty.UnsetValue;
string propertyName = parameter as string;
var result = new ObservableCollection<List<object>>();
var notify = value as INotifyCollectionChanged;
if (notify != null) notify.CollectionChanged += delegate { Reload(result, source, propertyName); };
Reload(result, source, propertyName);
return result;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
void Reload(ObservableCollection<List<object>> result, IEnumerable source, string propertyName)
{
result.Clear();
object previous = UnsetValue;
List<object> group = null;
foreach (object i in source)
{
object current = UnsetValue;
if (propertyName == null)
{
current = i;
}
else
{
try
{
var property = i.GetType().GetProperty(propertyName);
if (property != null) current = property.GetValue(i, null);
}
catch (AmbiguousMatchException) { }
}
if (!object.Equals(previous, current))
{
if (group != null) result.Add(group);
group = new List<object>();
}
group.Add(i);
previous = current;
}
if (group != null && group.Count > 0) result.Add(group);
}
}
last = null;
foreach (var option in list)
{
if (last != option)
newlist.Add(new Group(option, new[]));
newlist.Last().Add(option);
last = option;
}