我有一个非常大的对象列表(我自己定义的一个类)。我需要将此列表分成许多不同大小的不同分区。分区甚至可以只包含一个对象。基本上我试图根据这些对象之间的相似性来聚类这个列表。
以下是我的代码示例:
class Bar
{
public List<Foo> fooList = new List<Foo>();
// pseudocode of goal
List<List<Foo>> partitionedlist = new List<List<Foo>>();
List<Foo> partition1 = Partition(fooList.SelectMany(item.inputs.intersect(item2.inputs)));
}
class Foo
{
public List<String> inputs = new List<string>();
}
他们需要根据对象在其输入中的匹配数量(百分比)进行分区。名单。我希望能够限制分区的大小。
答案 0 :(得分:0)
我认为没有一种有效的方法可以使用LINQ来执行此操作,但您可以遍历所有Foo
并根据每个Foo
的相似程度创建存储桶桶的内容,当相似度太低时创建一个新桶。我使用每个Foo
的平均值和一个桶中的所有Foo
作为单个Foo
和一个桶(List<Foo>
)之间的相似性,并找到了带有最高相似度。
假设有一个函数用于计算两个Foo
之间的相似性(我使用了常见inputs
成员的数量除以inputs
的最大数量),你将它们放入桶中:< / p>
class Bar {
public List<Foo> fooList = new List<Foo>();
public List<List<Foo>> partitionedFoos;
public void PartitionFoos() {
partitionedFoos = Foo.PartitionFoos(fooList);
}
}
class Foo {
public List<String> inputs = new List<string>();
public double Similarity(Foo anotherFoo) {
return inputs.Intersect(anotherFoo.inputs).Count()/(double)(inputs.Count+anotherFoo.inputs.Count);
}
public static List<List<Foo>> PartitionFoos(List<Foo> foos) {
var answers = new List<List<Foo>>();
answers.Add(new List<Foo>());
var fooe = foos.GetEnumerator();
if (fooe.MoveNext()) {
answers[0].Add(fooe.Current);
while (fooe.MoveNext()) {
var curFoo = fooe.Current;
var max = answers.Select((lf, i) => (AvgSimilarity: lf.Average(f => f.Similarity(curFoo)), i)).MaxBy(si => si.AvgSimilarity);
if (max.AvgSimilarity < 0.4) // time for a new bucket!
answers.Add(new List<Foo> { curFoo });
else
answers[max.i].Add(curFoo);
}
}
return answers;
}
}
PS我使用了我已经定义的扩展方法来查找max:
public static T MaxBy<T, TKey>(this IEnumerable<T> src, Func<T, TKey> key, Comparer<TKey> keyComparer) => src.Aggregate((a, b) => keyComparer.Compare(key(a), key(b)) > 0 ? a : b);
public static T MaxBy<T, TKey>(this IEnumerable<T> src, Func<T, TKey> key) => src.Aggregate((a, b) => Comparer<TKey>.Default.Compare(key(a), key(b)) > 0 ? a : b);
public static T MinBy<T, TKey>(this IEnumerable<T> src, Func<T, TKey> key, Comparer<TKey> keyComparer) => src.Aggregate((a, b) => keyComparer.Compare(key(a), key(b)) < 0 ? a : b);
public static T MinBy<T, TKey>(this IEnumerable<T> src, Func<T, TKey> key) => src.Aggregate((a, b) => Comparer<TKey>.Default.Compare(key(a), key(b)) < 0 ? a : b);