# 通过算法大数据循环两两比较字符串，因为循环次数过多而导致程序过慢，如何解决？求救。。。

0

0
```using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.ConstrainedExecution;

namespace ZuoEr.Collections.Generic
{
internal static class HashHelpers
{
internal static readonly int[] primes = {
3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919,
1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591,
17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437,
187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263,
1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369};

[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
internal static bool IsPrime(int candidate)
{
if ((candidate & 1) != 0)
{
int limit = (int)Math.Sqrt(candidate);
for (int divisor = 3; divisor <= limit; divisor += 2)
{
if ((candidate % divisor) == 0)
return false;
}
return true;
}
return (candidate == 2);
}

[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
internal static int GetPrime(int min)
{
if (min < 0)
throw new ArgumentException("Arg_HTCapacityOverflow");
for (int i = 0; i < primes.Length; i++)
{
int prime = primes[i];
if (prime >= min) return prime;
}
for (int i = (min | 1); i < Int32.MaxValue; i += 2)
{
if (IsPrime(i))
return i;
}
return min;
}
}
}```

```using System;
using System.Collections.Generic;
using System.Text;

namespace ZuoEr.Collections.Generic
{
public sealed class HashTree<T>
{
private int count;
private int freeList;
private int freeCount;
private int[] buckets;
private Eny<T, HashTree<T>>[] entries;
private IEqualityComparer<T> comparer;
private HashTree<T> parent;

private struct Eny<K, V>
{
public K key;
public V value;
public bool active;
public int hashCode;
public int next;
}

private HashTree(HashTree<T> parent, IEqualityComparer<T> comparer)
{
this.parent = parent;
this.comparer = comparer;
}
private IEqualityComparer<T> Comparer
{
get { return this.comparer ?? (this.comparer = EqualityComparer<T>.Default); }
}
private void GetHashIndex(T item, out int num, out int idx)
{
idx = (num = this.Comparer.GetHashCode(item) & 0x7fffffff) % this.buckets.Length;
}
private bool GetExists(T item, int num, int idx)
{
return this.entries[idx].hashCode == num && this.Comparer.Equals(item, this.entries[idx].key);
}
private void Initialize()
{
this.entries = new Eny<T, HashTree<T>>[0];
this.Resize();
}
private void Resize()
{
var prime = HashHelpers.GetPrime(this.count * 2);
var buckets_temp = new int[prime];
for (var i = 0; i < buckets_temp.Length; i++)
buckets_temp[i] = -1;
var entries_temp = new Eny<T, HashTree<T>>[prime];
Array.Copy(this.entries, 0, entries_temp, 0, this.count);
for (var i = 0; i < this.count; i++)
{
var p = entries_temp[i].hashCode % prime;
entries_temp[i].next = buckets_temp[p];
buckets_temp[p] = i;
}
this.buckets = buckets_temp;
this.entries = entries_temp;
}

public int Count
{
get { return this.count - this.freeCount; }
}
public int Level
{
get { return this.Parent != null ? this.Parent.Level + 1 : 0; }
}
public IEnumerable<T> Values
{
get
{
int i;

if ((i = this.Count) == 0) yield break;

foreach (var item in this.entries)
{
if (item.active)
{
i--;
yield return item.key;
}

if (i == 0)
break;
}
}
}
public HashTree<T> Parent
{
get { return this.parent; }
}
public HashTree<T> this[T item]
{
get
{
HashTree<T> r;
if (this.TryGetValue(item, out r)) return r;
throw new KeyNotFoundException();
}
}
public HashTree<T> Add(T item)
{
return this.Insert(item, false);
}
public HashTree<T> Insert(T item, bool ignoreRepeat)
{
if (item == null)
throw new ArgumentNullException();

if (this.buckets == null)
this.Initialize();

int num, idx, freeList;
this.GetHashIndex(item, out num, out idx);

for (var i = this.buckets[idx]; i >= 0; i = this.entries[i].next)
{
if (this.GetExists(item, num, i))
{
if (ignoreRepeat) return this.entries[i].value;
throw new ArgumentException();
}
}

if (this.freeCount > 0)
{
freeList = this.freeList;
this.freeList = this.entries[freeList].next;
this.freeCount--;
}
else
{
if (this.count == this.entries.Length)
{
this.Resize();
idx = num % this.buckets.Length;
}
freeList = this.count;
this.count++;
}

var r = new HashTree<T>(this, this.comparer);
this.entries[freeList].active = true;
this.entries[freeList].hashCode = num;
this.entries[freeList].next = this.buckets[idx];
this.entries[freeList].key = item;
this.entries[freeList].value = r;
this.buckets[idx] = freeList;

return r;
}
public bool TryGetValue(T item, out HashTree<T> result)
{
if (item == null)
throw new ArgumentNullException();

if (this.buckets != null)
{
int num, idx;
this.GetHashIndex(item, out num, out idx);

for (var i = this.buckets[idx]; i >= 0; i = this.entries[i].next)
{
if (this.GetExists(item, num, i))
{
result = this.entries[i].value;
return true;
}
}

}

result = null;
return false;
}
public bool Contains(T item)
{
if (item == null)
throw new ArgumentNullException();

if (this.buckets != null)
{
int num, idx;
this.GetHashIndex(item, out num, out idx);

for (var i = this.buckets[idx]; i >= 0; i = this.entries[i].next)
{
if (this.GetExists(item, num, i)) return true;
}
}

return false;
}
public bool Remove(T item)
{
if (item == null)
throw new ArgumentNullException();

if (this.buckets != null)
{
int num, idx, fit = -1;
this.GetHashIndex(item, out num, out idx);

for (var i = this.buckets[idx]; i >= 0; i = this.entries[i].next)
{
if (this.GetExists(item, num, i))
{
if (fit < 0)
this.buckets[idx] = this.entries[i].next;
else
this.entries[fit].next = this.entries[i].next;
this.entries[i].active = false;
this.entries[i].hashCode = -1;
this.entries[i].next = this.freeList;
this.entries[i].key = default(T);
this.entries[i].value = null;
this.freeList = i;
this.freeCount++;
return true;
}
fit = i;
}
}

return false;
}
public HashTree() : this(null, null) { }
public HashTree(IEqualityComparer<T> comparer) : this(null, comparer) { }
}
}```

```// 获得差级
public static IEnumerable<DynamicObject> Except<TKey>(this IEnumerable<DynamicObject> owner, IEnumerable<DynamicObject> child, IEnumerable<string> properties, Func<object, TKey> keySelector, IEqualityComparer<TKey> comparer)
{
var hash = new HashTree<TKey>(comparer);

// 将比较的属性 依次存入
foreach (var item in child)
{
var node = hash;

foreach (var meta in properties)
{
node = node.Insert(keySelector.Invoke(((IDictionary<string, object>)item)[meta]), true);
}
}

// 取出差级
foreach (var item in owner)
{
var node = hash;
var resl = true;

foreach (var meta in properties)
{
if (!(resl &= node.TryGetValue(keySelector.Invoke(((IDictionary<string, object>)item)[meta]), out node)))
break;
}

if (!resl) yield return item;
}
}```

1. 使用 IDictionary<string, IDictionary<string, ....>>

2. 使用 System.Data.DataTable + System.Data.DataRelation

@过于执著: 我先研究下你的代码是否符合我的需求，不明白的再问下你。

@枫轻: 其实使用 System.Data.DataTable + System.Data.DataRelation

@过于执著: 呵呵，看着你给的代码都不知道怎么装逼，不知道如何下手。

@枫轻: 你先把 第一段代码, 第二段代码 拷贝,

@过于执著: 我修改了问题，添加了表结构和可能要比较的列，你看下怎么定义对象和比较的属性。

@枫轻: 两个数组? 属性都一样? 和谁比写以下,

@过于执著: 两两比较相应的列，这个比较的时候会通过一个算法计算出相似度，然后通过一个公式计算所有的列的综合值。这个计算我们已经定义好了，关键就是那个对比过程特别慢。

@过于执著: 比如这样比较：单个字段的时候，第一行的字段1和第二行的字段2比较；多个字段的时候就类似相应列的比较。我已经修改了问题，贴出了表结构，你看一下。

@枫轻: 没听懂 也没看懂,

@枫轻: 把你的代码贴出来

1. Model

2. 循环

3. 所谓的 相似度 的算法.

@过于执著:

try
{

string sqlGroup = string.Format("{0}='{1}'", HCZB.DBDefinition.GroupTable.Column_Active.Name, "1");
List<HCZB.Business.Group> groupList = HCZB.Business.Group.GetAllListBy(sqlGroup, "");

if (groupList[0].Active == 1)
{
string sql = string.Format("{0}='{1}'", HCZB.DBDefinition.MatchFieldTable.Column_GroupId.Name, groupList[0].GroupId);
List<HCZB.Business.MatchField> ds_matchfield = HCZB.Business.MatchField.GetAllListBy(sql, "");

string[] c = new string[ds_matchfield.Count];
string[] d = new string[ds_matchfield.Count];
string[] e = new string[ds_matchfield.Count];
for (int i = 0; i < ds_matchfield.Count; i++)
{
c[i] = ds_matchfield[i].MatchThreshold.ToString();
d[i] = ds_matchfield[i].Weight.ToString();
e[i] = ds_matchfield[i].Field.ToString();
}

DataSet ds = HCZB.Business.CustomerInfo.GetAllCustomerInfo();//获取表的所有数据
//DateTime dt1 = DateTime.Now;
if (ds != null && ds.Tables[0].Rows.Count > 0)
{
int i = 0;
int j = 0;
int masterindex = 0;
while (i < ds.Tables[0].Rows.Count)//第一个循环
{
masterindex++;

List<HCZB.Business.OutPutTable> outPutTableList = HCZB.Business.OutPutTable.GetAllListBy(string.Format("{0}='{1}'", HCZB.DBDefinition.OutPutTableTable.Column_Identifier.Name, int.Parse(ds.Tables[0].Rows[i]["id"].ToString())), "");
if (outPutTableList.Count == 0)
{
HCZB.Business.OutPutTable outPutTable = new HCZB.Business.OutPutTable();
outPutTable.Identifier = int.Parse(ds.Tables[0].Rows[i]["id"].ToString());
outPutTable.Masterindex = masterindex;
outPutTable.Linkedtime = DateTime.Now;
outPutTable.MatchRate = "0%";
outPutTable.Insert();

string[] a = new string[e.Length];
for (int k = 0; k < e.Length; k++)
{
a[k] = ds.Tables[0].Rows[i][e[k]].ToString();
}

j = i + 1;

string MemGender = ds.Tables[0].Rows[i]["MemGender"].ToString();

DataRow[] dr = ds.Tables[0].Select(string.Format("MemGender='{0}' or ISNULL(MemGender,'')='{0}'", MemGender));
DataTable dt2 = ToDataTable(dr);

while (j < dt2.Rows.Count)//第二个循环
{
string[] b = new string[e.Length];
for (int k = 0; k < e.Length; k++)
{
b[k] = dt2.Rows[j][e[k]].ToString();
}

float value = StringCompareOthers(a, b, c, d);//这里是用算法
if (value > groupList[0].IntegrateValue)
{
List<HCZB.Business.OutPutTable> outPutTableList1 = HCZB.Business.OutPutTable.GetAllListBy(string.Format("{0}='{1}'", HCZB.DBDefinition.OutPutTableTable.Column_Identifier.Name, int.Parse(dt2.Rows[j]["id"].ToString())), "");
if (outPutTableList1.Count == 0)
{
HCZB.Business.OutPutTable outPutTable1 = new HCZB.Business.OutPutTable();
outPutTable1.Identifier = int.Parse(dt2.Rows[j]["id"].ToString());
outPutTable1.Masterindex = masterindex;
outPutTable1.Linkedtime = DateTime.Now;
outPutTable1.MatchRate = (value * 100).ToString("0.00") + "%";
outPutTable1.Insert();

}
else
{
List<HCZB.Business.OutPutTable> list = HCZB.Business.OutPutTable.GetAllListBy("", "Masterindex desc");
masterindex = int.Parse(list[0].Masterindex.ToString());
}
}

j++;
}
}
else
{
List<HCZB.Business.OutPutTable> list = HCZB.Business.OutPutTable.GetAllListBy("", "Masterindex desc");
masterindex = int.Parse(list[0].Masterindex.ToString());
}

i++;
}

ds.Dispose();
}

}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}

@枫轻: StringCompareOthers 方法也贴出来下,

@枫轻: 我还是仅给你, 你的 "解决方案" 吧,

1.只需要访问一条数据的地方, 不要把整个集合都拿过来 如 : groupList , list 变量

2.把需要访问 Count  的地方, 不要把整个集合都拿过来 如 : outPutTableList, outPutTableList1  变量

3.把 循环内 的数据库访问 提到外面来 如: OutPutTable

@过于执著: 那个相似度算法是levenshtein distance,你可以查查，两个字符串的相似度的计算。

@过于执著: 说实话 你只要告诉他怎么降低时间复杂度就好了

0

nicky0227 | 园豆：1069 (小虾三级) | 2015-02-15 09:13

@枫轻: 对比列加索引之后直接用sql语句要快的多

@nicky0227: 试过用存储过程，加了索引速度还是没有程序端快，现在的主要问题是，因为用了双循环导致循环对比次数过程过多而导致程序过慢。

@nicky0227: 我们的那些比较列是动态获取的。

@枫轻: “通过算法找出相似度比较高的数据” 这应该是你想出来的解决方案吧！你这个方案究竟是想解决什么问题？

@Launcher: 通过算法已经可以找出相似度比较的内容。就是找出相似的数据。

@枫轻: 你提问题的方式有问题，根据你目前提供的信息，我给你梳理下。

@Launcher: 目前的规则是，第一条数据和其他数据进行对比，匹配的记录存储在output表中，第一个循环完成之后，把所有未匹配的找到，从未匹配的数据中又执行第一次的规则从第一条开始和其他剩余的比较，以此类推，我们现在需要能够提高效率的解决方案.

@枫轻: 按照 a,b,c,d,e,f 来举例：

@Launcher: 嗯，是这样的。我们程序是这样设计的，双循环跑(内循环外循环)，

int[] arr=new int[a,b,c,d,e,f];

for(int i=0;i<arr.length;i++)

{

string a=arr[i];

for(int j=i+1;j<arr.length;j++)

{

string b=arr[j];

//算法比较

int value=算法(a,b);

if(value>0.8)

{

入库

}

}

}

@枫轻:

@Launcher: 就是这样的逻辑，但是实现起来方式不是，我们那个代码虽然那样循环，但是如果已经插入过的数据就不再插入的，有做判断。

@枫轻: 按照你写的代码，当先拿出 arr[0]（a）匹配完后，第二次你拿出的是 arr[1](b)，而不是从未匹配集合(c,e,f)中取出 c 来匹配。

@Launcher: 不好意思，那个代码不是完整的，如果第二次你拿出是arr[1](b)，则判断数据库中是否已有匹配，有则直接跳过，进入下一次循环。

@枫轻: 我们假设在集合{a,b,c,d,e,f}中，所有元素的相似度都是 1，那么第一次循环就能得到最终结果，但是按照你写的代码，你还需要做 5 次查询。

@枫轻:

@Launcher: 是的。

@Launcher: 没有考虑到这个推导，感觉应该是可以的。

@枫轻: 你不用感觉，你写的代码就默认了这个推导是成立的，因此你写的算法与集合中记录的顺序无关；否则，你的算法就依赖集合中记录的顺序，那么你写的算法就是错误的。如果是前者，那么你的算法就会产生 5 次无效的查询操作，这是可以优化的地方。

0

LiuKaiFa | 园豆：1491 (小虾三级) | 2015-02-17 22:17
0

您需要登录以后才能回答，未注册用户请先注册