我有一个很大的对象列表(我已经定义了自己的类(。我需要将此列表划分为许多不同大小的不同分区。一个分区甚至只能包含一个对象。基本上,我试图基于这些对象之间的相似性数量来聚集此列表。
这是我的代码的一个示例,例如:
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>();
}
需要根据对象在其"输入"列表中具有的匹配项(百分比(进行分区。我也希望也能够限制分区的大小。
我认为没有一种有效的方法可以使用Linq来执行此操作,但是您可以根据每个Foo
s循环并根据每个Foo
与内容的相似方式创建存储桶桶,并在相似性太低时创建一个新的水桶。我将每个 Foo
的平均值与所有 Foo
s的平均值一起用作单个 Foo
和一个水桶( List<Foo>
(之间的相似性,并找到了具有最高相似性的水桶。
假设一个用于计算两个 Foo
s之间相似性的函数(我使用的是inputs
成员的数量除以inputs
的最大计数(,您将它们放入存储桶中:
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我使用了我定义的扩展方法来查找最大值:
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);