问题说明:有这样形式的字符串”129384/283901/123903 293120/293092/391032 232218/312398/962519………631782/239715/123987″ . 其中129384/283901/123903为1组,中间用空格隔开.一共是2万组这样的数据.每组数据分3段,用”/”隔开.现在要做的是把每组数据的每段提出1个数字,组成1个3位数,不管重复.只要组合全就行.怎么做效率才最高呢? 小弟本人写了代码,可是效率太低了.
这有部分代码 请高手帮忙!
ArrayList ay_shuju = new ArrayList();
string[] str_shuju;
string[] str_zu;
string str,str_jieguo;
string mystr = “129384/283901/123903 293120/293092/391032 232218/312398/962519………631782/239715/123987″; // 2万组 用空格隔开
str_shuju = mystr.Split(” “);
for (int j = 0; j < str_shuju.Length; j++)
{
str_zu = str_shuju[j].Split(“/”);
for (int ii = 0; ii < str_zu[0].Length; ii++)
{
for (int jj = 0; jj < str_zu[1].Length; jj++)
{
for (int kk = 0; kk < str_zu[2].Length; kk++)
{
str_jieguo = str_zu[0].Substring(ii, 1) + str_zu[1].Substring(jj, 1) + str_zu[2].Substring(kk, 1);
str = str + ” ” + str_jieguo;
if (!ay_shuju.Contains(str_jieguo))
{
ay_shuju.Add(str_jieguo);
}
}
}
}
}
这有部分代码 请高手帮忙!
ArrayList ay_shuju = new ArrayList();
string[] str_shuju;
string[] str_zu;
string str,str_jieguo;
string mystr = “129384/283901/123903 293120/293092/391032 232218/312398/962519………631782/239715/123987″; // 2万组 用空格隔开
str_shuju = mystr.Split(” “);
for (int j = 0; j < str_shuju.Length; j++)
{
str_zu = str_shuju[j].Split(“/”);
for (int ii = 0; ii < str_zu[0].Length; ii++)
{
for (int jj = 0; jj < str_zu[1].Length; jj++)
{
for (int kk = 0; kk < str_zu[2].Length; kk++)
{
str_jieguo = str_zu[0].Substring(ii, 1) + str_zu[1].Substring(jj, 1) + str_zu[2].Substring(kk, 1);
str = str + ” ” + str_jieguo;
if (!ay_shuju.Contains(str_jieguo))
{
ay_shuju.Add(str_jieguo);
}
}
}
}
}
解决方案
35
每一个区段都是长度固定的数字吗?都是6位数字/6位数字/6位数字这种格式吗?
129384/283901/123903
10
理论上只需要一次遍历,效率为o(n/3) n为字符串总长度。
for (var i = 0; i < txt.Length; i += 20 + spilitLength) { list.Add(String.Format("{0}[1}{2}",txt[i],txt[i+7],txt[i+14])); }
这个性能差点,但是精简代码,只需要1行
20
从算法上,你的做法(3个嵌套循环作组合)并没有问题。
但具体实现上,有几个瓶颈:
str = str + " " + str_jieguo; // 1 if (!ay_shuju.Contains(str_jieguo)) // 2 { ay_shuju.Add(str_jieguo); }
1、str要合并约4百万次,将产生4百万个垃圾字符串。改进方法就是用StringBuilder。
2、ay_shuju是ArrayList,那么Contains将遍历ArrayList(每次ArrayList.Contains可能要查百万级数据)。改进方法就是用HashSet<string>。
15
string mystr = "129384/283901/123903 293120/293092/391032 232218/312398/962519 631782/239715/123987"; // 2万组 用空格隔开 System.Collections.Generic.List<string> ay_shuju = new System.Collections.Generic.List<string>(1000); int groupCount = (mystr.Length + 1) / (3 * 6 + 2 + 1); byte[] isNumber = new byte[1000]; string str = new string(" ", groupCount * (6 * 6 * 6 * 4)); fixed (byte* isNumberFixed = isNumber) fixed (char* mystrFixed = mystr, strFixed = str) { for (char* group = mystrFixed, end = mystrFixed + groupCount * (3 * 6 + 2 + 1), strWrite = strFixed + 1; group != end; group += (3 * 6 + 2 + 1)) { char* ii = group, iiEnd = group + 6; do { int iiNumber = (*ii - "0") * 100; char* jj = group + 7, jjEnd = jj + 6; do { int jjNumber = iiNumber + (*jj - "0") * 10; char* kk = group + (7 * 2), kkEnd = kk + 6; do { int number = jjNumber + (*kk - "0"); *strWrite = *ii; *(strWrite + 1) = *jj; *(strWrite + 2) = *kk; if (isNumberFixed[number] == 0) { ay_shuju.Add(new string(strWrite, 0, 3)); isNumberFixed[number] = 1; } strWrite += 4; } while (++kk != kkEnd); } while (++jj != jjEnd); } while (++ii != iiEnd); } }
5
假如需要考虑非法数据造成内存写安全问题,可以加一个判断 (uint)number < 1000 ,或直接使用isNumber[number]让它抛异常
string mystr = "129384/283901/123903 293120/293092/391032 232218/312398/962519 631782/239715/123987"; // 2万组 用空格隔开 System.Collections.Generic.List<string> ay_shuju = new System.Collections.Generic.List<string>(1000); int groupCount = (mystr.Length + 1) / (3 * 6 + 2 + 1); byte[] isNumber = new byte[1000]; string str = new string(" ", groupCount * (6 * 6 * 6 * 4)); fixed (byte* isNumberFixed = isNumber) fixed (char* mystrFixed = mystr, strFixed = str) { for (char* group = mystrFixed, end = mystrFixed + groupCount * (3 * 6 + 2 + 1), strWrite = strFixed + 1; group != end; group += (3 * 6 + 2 + 1)) { char* ii = group, iiEnd = group + 6; do { int iiNumber = (*ii - "0") * 100; char* jj = group + 7, jjEnd = group + (7 + 6); do { int jjNumber = iiNumber + (*jj - "0") * 10; char* kk = group + (7 * 2), kkEnd = group + (7 * 2 + 6); do { int number = jjNumber + (*kk - "0"); *strWrite = *ii; *(strWrite + 1) = *jj; *(strWrite + 2) = *kk; if ((uint)number < 1000 && isNumberFixed[number] == 0) { ay_shuju.Add(new string(strWrite, 0, 3)); isNumberFixed[number] = 1; } strWrite += 4; } while (++kk != kkEnd); } while (++jj != jjEnd); } while (++ii != iiEnd); } }
5
string txt = "129384/283901/123903 293120/293092/391032 232218/312398/962519"; char[] txt2 = txt.ToCharArray();
每段中摘抄字符,从 txt2 数组处理即可。
很显然,第 i 组的第 j 段字符的txt2中的下标位置是在 i*21 +1 +j*7。假如这个公式不对,请本人修改,搞懂它意思就行了。
10
不管你总体数据有多少,只要一组数据做对了,其他全部的也就都对了
他实际就是求个笛卡尔积
他实际就是求个笛卡尔积
var s = "129384/283901/123903"; var a = s.Split("/"); var q = from x in a[0].ToArray() from y in a[1].ToArray() from z in a[2].ToArray() select (x-"0") * 100 + (y - "0") * 10 + z-"0"; foreach (var c in q) Console.WriteLine(c);
121 122 123 129 120 123 181 182 183 189 180 183 131 132 133 139 130 133 191 192 193 199 190 193 101 102 103 109 100 103 111 112 113 119 110 113 221 222 223 229 220 223 281 282 283 289 280 283 231 232 233 239 230 233 291 292 293 299 290 293 201 202 203 209 200 203 211 212 213 219 210 213 921 922 923 929 920 923 981 982 983 989 980 983 931 932 933 939 930 933 991 992 993 999 990 993 901 902 903 909 900 903 911 912 913 919 910 913 321 322 323 329 320 323 381 382 383 389 380 383 331 332 333 339 330 333 391 392 393 399 390 393 301 302 303 309 300 303 311 312 313 319 310 313 821 822 823 829 820 823 881 882 883 889 880 883 831 832 833 839 830 833 891 892 893 899 890 893 801 802 803 809 800 803 811 812 813 819 810 813 421 422 423 429 420 423 481 482 483 489 480 483 431 432 433 439 430 433 491 492 493 499 490 493 401 402 403 409 400 403 411 412 413 419 410 413