我正在寻找最快的算法:
目标:输出一行中找到的对的总次数。各个元素可以是任何给定行上的任何顺序。
INPUT:
a;b;c;d
a;e;f;g
a;b;f;h
输出
a;b = 2
a;c = 1
a;d = 1
a;e = 1
a;f = 2
a;g = 1
b;c = 1
b;d = 1
我正在用C#编程,我有一个嵌套的for循环添加做一个常见的字典字典,其中字符串就像a; b,当发现一个事件时,它会添加到现有的int tally或添加一个新的at tally = 0。
请注意:
a;b = 1
b;a = 1
应该简化为:
a;b = 1
我愿意使用其他语言,输出是一个纯文本文件,我将其提供给Gephi可视化工具。
奖励:非常有兴趣知道这个特定算法的名称,如果它在那里。很确定它是。
String[] data = File.ReadAllLines(@"C:\input.txt");
Dictionary<string, int> ress = new Dictionary<string, int>();
foreach (var line in data)
{
string[] outStrings = line.Split(';');
for (int i = 0; i < outStrings.Count(); i++)
{
for (int y = 0; y < outStrings.Count(); y++)
{
if (outStrings[i] != outStrings[y])
{
try
{
if (ress.Any(x => x.Key == outStrings[i] + ";" + outStrings[y]))
{
ress[outStrings[i] + ";" + outStrings[y]] += 1;
}
else
{
ress.Add(outStrings[i] + ";" + outStrings[y], 0);
}
}
catch (Exception)
{
}
}
}
}
}
foreach (var val in ress)
{
Console.WriteLine(val.Key + "----" + val.Value);
}
答案 0 :(得分:3)
我认为你的内部循环应该从i + 1
开始,而不是再次从0
开始,外部循环应该只运行到Length - 1
,因为最后一项将在内循环。此外,当您添加新项目时,您应该添加值1
,而不是0
(因为我们添加它的全部原因是因为我们找到了一个)。
您还可以将密钥存储到字符串中一次,而不是在比较和分配期间进行多个连接,并且可以使用ContainsKey
方法确定密钥是否已存在。
此外,您可能需要考虑避免空catch
块,除非您确定不关心是否或出现了什么问题。如果我期待一个异常并且知道如何处理它,那么我就会抓住那个例外,否则我只会让它冒出来。
以下是修改代码以查找所有配对及其计数的一种方法:
<强>更新强>
我添加了一张支票以确保&#34;对#34;密钥总是排序,因此&#34; b; a&#34;成为&#34; a; b&#34;。这不是您的示例数据中的问题,但我将数据扩展为包含b;a;a;b;a;b;a;
之类的行。另外,我向StringSplitOptions.RemoveEmptyEntries
方法添加了Split
,以处理行以;
开头或结尾的情况(否则空值会产生像";a"
这样的对。)< / p>
private static void Main()
{
var data = File.ReadAllLines(@"f:\public\temp\temp.txt");
var pairCount = new Dictionary<string, int>();
foreach (var line in data)
{
var lineItems = line.Split(new[] {';'}, StringSplitOptions.RemoveEmptyEntries);
for (var outer = 0; outer < lineItems.Length - 1; outer++)
{
for (var inner = outer + 1; inner < lineItems.Length; inner++)
{
var outerComparedToInner = string.Compare(lineItems[outer],
lineItems[inner], StringComparison.Ordinal);
// If both items are the same character, ignore them and keep looping
if (outerComparedToInner == 0) continue;
// Create the pair such that the lower of the two
// values is first, so that "b;a" becomes "a;b"
var thisPair = outerComparedToInner < 0
? $"{lineItems[outer]};{lineItems[inner]}"
: $"{lineItems[inner]};{lineItems[outer]}";
if (pairCount.ContainsKey(thisPair))
{
pairCount[thisPair]++;
}
else
{
pairCount.Add(thisPair, 1);
}
}
}
}
Console.WriteLine("Pair\tCount\n----\t-----");
foreach (var val in pairCount.OrderBy(i => i.Key))
{
Console.WriteLine($"{val.Key}\t{val.Value}");
}
Console.Write("\nDone!\nPress any key to exit...");
Console.ReadKey();
}
<强>输出强>
给定包含样本数据的文件,输出为:
答案 1 :(得分:1)
@mrmcgreg,最后将实现更改为ECLAT algorythm后,所有内容都会在几秒钟而不是几小时内运行。
基本上对于每个唯一标记,跟踪找到这些标记的LINE NUMBERS,并简单地将这对数字列表与组合对相交以获得计数。
Dictionary<string, List<int>> uniqueTagList = new Dictionary<string, List<int>>();
foreach (var uniqueTag in uniquetags)
{
List<int> lineNumbers = new List<int>();
foreach (var item in data.Select((value, i) => new { i, value }))
{
var value = item.value;
var index = item.i;
//split data into tags
var tags = item.ToString().Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var tag in tags)
{
if (uniqueTag == tag)
{
lineNumbers.Add(index);
}
}
}
//remove all having support threshold.
if (lineNumbers.Count > 5)
{
uniqueTagList.Add(uniqueTag, lineNumbers);
}
}