【问题标题】:Split the string and join all first elements then second element and so on in c#在c#中拆分字符串并连接所有第一个元素,然后是第二个元素,依此类推
【发布时间】:2018-02-17 04:20:23
【问题描述】:

我有一个这样的字符串 -

var roleDetails = "09A880C2-8732-408C-BA09-4AD6F0A65CE9^Z:WB:SELECT_DOWNLOAD:0000^Product Delivery - Download^1,24B11B23-1669-403F-A24D-74CE72DFD42A^Z:WB:TRAINING_SUBSCRIBER:0000^Training Subscriber^1,6A4A6543-DB9F-46F2-B3C9-62D69D28A0B6^Z:WB:LIC_MGR_HOME_REDL:0000^License Manager - Home use^1,76B3B165-0BB4-4E3E-B61F-0C0292342CE2^Account Admin^Account Admin^1,B3C0CE51-00EE-4A0A-B208-98653E21AE11^Z:WB:1BENTLEY_ISA_ADMIN:0000^Co-Administrator^1,CBA225BC-680C-4627-A4F6-BED401682816^ReadOnly^ReadOnly^1,D80CF5CF-CB6E-4424-9D8F-E29F96EBD4C9^Z:WB:MY_SELECT_CD:0000^Product Delivery - DVD^1,E0275936-FBBB-4775-97D3-9A7D19D3E1B4^Z:WB:LICENSE_MANAGER:0000^License Manager^1";

用 "," 分割它会返回这个 -

[0] "09A880C2-8732-408C-BA09-4AD6F0A65CE9^Z:WB:SELECT_DOWNLOAD:0000^Product Delivery - Download^1"
[1] "24B11B23-1669-403F-A24D-74CE72DFD42A^Z:WB:TRAINING_SUBSCRIBER:0000^Training Subscriber^1"
[2] "6A4A6543-DB9F-46F2-B3C9-62D69D28A0B6^Z:WB:LIC_MGR_HOME_REDL:0000^License Manager - Home use^1"
[3] "76B3B165-0BB4-4E3E-B61F-0C0292342CE2^Account Admin^Account Admin^1"    
[4] "B3C0CE51-00EE-4A0A-B208-98653E21AE11^Z:WB:1BENTLEY_ISA_ADMIN:0000^Co-Administrator^1"  
[5] "CBA225BC-680C-4627-A4F6-BED401682816^ReadOnly^ReadOnly^1"
[6] "D80CF5CF-CB6E-4424-9D8F-E29F96EBD4C9^Z:WB:MY_SELECT_CD:0000^Product Delivery - DVD^1"
[7] "E0275936-FBBB-4775-97D3-9A7D19D3E1B4^Z:WB:LICENSE_MANAGER:0000^License Manager^1"

所有元素都包含克拉 (^)。所以用 ^ 符号进一步分割每个元素将返回四个元素。

但我想加入所有第一个元素,然后加入所有第二个元素,然后加入第三个元素,依此类推,得到这样的结果 -

[0]: 09A880C2-8732-408C-BA09-4AD6F0A65CE9, 24B11B23-1669-403F-A24D-74CE72DFD42A, 6A4A6543-DB9F-46F2-B3C9-62D69D28A0B6, 76B3B165-0BB4-4E3E-B61F-0C0292342CE2, B3C0CE51-00EE-4A0A-B208-98653E21AE11, CBA225BC-680C-4627-A4F6-BED401682816, D80CF5CF-CB6E-4424-9D8F-E29F96EBD4C9, E0275936-FBBB-4775-97D3-9A7D19D3E1B4

[1]: Z:WB:SELECT_DOWNLOAD:0000,Z:WB:TRAINING_SUBSCRIBER:0000, Z:WB:LIC_MGR_HOME_REDL:0000,Account Admin, Z:WB:1BENTLEY_ISA_ADMIN:0000, ReadOnly, Z:WB:MY_SELECT_CD:0000, Z:WB:LICENSE_MANAGER

[2]: Product Delivery - Download, Training Subscriber, License Manager - Home use, Account Admin, Co-Administrator, ReadOnly, Product Delivery - DVD, License Manager
[3]: 1,1,1,1,1,1,1,1

实现这一目标的最快和最简单的方法是什么?

编辑

这是我迄今为止尝试过的 -

var rolearray = roleDetails.Split(',').Select(s => s.Split('^')).Select(a => new { RoleId = a[0], RoleNme = a[1], FriendlyName = a[2], IsUserInRole = a[3] });

但这又不是以我需要的方式返回。但我想加入所有 a[0]s ,然后加入所有 a[1] 等等

解决方案: 在比较解决方案并循环运行 10 次以查看性能后,我发现 Jamiec 建议的解决方案花费的时间更少。所以选择这个解决方案。

【问题讨论】:

  • 能否请您至少发布您自己的第一次尝试来解决这个问题?
  • 您的 7 个结果拆分后的集合返回 4 个元素?您想要所有第一个元素彼此相邻吗? (在预期结果中看起来不像那样)。老实说,我不太明白你在问什么
  • 你试过oldscool方式吗,使用2个循环?=!
  • 老实说,如果您要按列分组,我会说只是创建一个您填写的课程:)
  • @MongZhu:我不同意 linq 使这变得神秘。 OP 试图将操作连线使其变得神秘。使用 Linq 很好地分开的代码行不应该是不可读的(目前正在撰写一个答案来证明我的观点,给我一分钟:))

标签: c# .net arrays linq


【解决方案1】:

纯 LINQ 解决方案:

roleDetails.Split(',')
    .SelectMany(x => x.Split('^').Select((str, idx) => new {str, idx}))
    .GroupBy(x => x.idx)
    .Select(grp => string.Join(", ", grp.Select(x => x.str)))

【讨论】:

  • 唯一不使用固定/硬编码索引的解决方案! +1 表示在某天输入应该改变时它不会中断。
【解决方案2】:

最简单的方法就是这样做:

var split = roleDetails.Split(',')
                .Select(x => x.Split('^').ToArray())
                .ToArray();

然后你可以像 multi dimensional 锯齿状数组一样访问元素

Console.WriteLine(split[0][0]);
// result: 09A880C2-8732-408C-BA09-4AD6F0A65CE9

现场示例:http://rextester.com/NEUVOR15080

如果你想要所有元素分组

Console.WriteLine(String.Join(",",split.Select(x => x[0])));
Console.WriteLine(String.Join(",",split.Select(x => x[1])));
Console.WriteLine(String.Join(",",split.Select(x => x[2])));
Console.WriteLine(String.Join(",",split.Select(x => x[3])));

现场示例:http://rextester.com/BZXLG67151

【讨论】:

  • 与其他解决方案比较,运行了10次,发现耗时少了很多。
  • @AnilPurswani 如果性能对您至关重要,则应避免使用 LINQ。使用 StringBuilders 的一次性方法将是最快的。
  • string.Split(char[]) 已经返回和数组。 msdn.microsoft.com/en-us/library/b873y76a(v=vs.110).aspx
  • 这是一个锯齿状数组而不是多维数组。
【解决方案3】:

这里可以使用 Linq 的 Aggregate 和 Zip 扩展方法。

聚合:对集合中的每个元素执行指定的操作,同时将结果向前传递。

Zip: Zip 扩展方法作用于两个集合。它将两个系列中的每个元素一起处理。

var roleDetails = "09A880C2-8732-408C-BA09-4AD6F0A65CE9^Z:WB:SELECT_DOWNLOAD:0000^Product Delivery - Download^1,24B11B23-1669-403F-A24D-74CE72DFD42A^Z:WB:TRAINING_SUBSCRIBER:0000^Training Subscriber^1,6A4A6543-DB9F-46F2-B3C9-62D69D28A0B6^Z:WB:LIC_MGR_HOME_REDL:0000^License Manager - Home use^1,76B3B165-0BB4-4E3E-B61F-0C0292342CE2^Account Admin^Account Admin^1,B3C0CE51-00EE-4A0A-B208-98653E21AE11^Z:WB:1BENTLEY_ISA_ADMIN:0000^Co-Administrator^1,CBA225BC-680C-4627-A4F6-BED401682816^ReadOnly^ReadOnly^1,D80CF5CF-CB6E-4424-9D8F-E29F96EBD4C9^Z:WB:MY_SELECT_CD:0000^Product Delivery - DVD^1,E0275936-FBBB-4775-97D3-9A7D19D3E1B4^Z:WB:LICENSE_MANAGER:0000^License Manager^1";
var rolearray = roleDetails.Split(',')
            .Select(s => s.Split('^'))
            .Aggregate((s1Array, s2Array) => s1Array.Zip(s2Array, (s1, s2) => s1 + "," + s2).ToArray());

【讨论】:

  • 不错的解决方案,但这种方法所花费的时间比其他方法要多。无论如何,感谢您提供新型解决方案
【解决方案4】:
string roleDetails = "09A880C2-8732-408C-BA09-4AD6F0A65CE9^Z:WB:SELECT_DOWNLOAD:0000^Product Delivery - Download^1,24B11B23-1669-403F-A24D-74CE72DFD42A^Z:WB:TRAINING_SUBSCRIBER:0000^Training Subscriber^1,6A4A6543-DB9F-46F2-B3C9-62D69D28A0B6^Z:WB:LIC_MGR_HOME_REDL:0000^License Manager - Home use^1,76B3B165-0BB4-4E3E-B61F-0C0292342CE2^Account Admin^Account Admin^1,B3C0CE51-00EE-4A0A-B208-98653E21AE11^Z:WB:1BENTLEY_ISA_ADMIN:0000^Co-Administrator^1,CBA225BC-680C-4627-A4F6-BED401682816^ReadOnly^ReadOnly^1,D80CF5CF-CB6E-4424-9D8F-E29F96EBD4C9^Z:WB:MY_SELECT_CD:0000^Product Delivery - DVD^1,E0275936-FBBB-4775-97D3-9A7D19D3E1B4^Z:WB:LICENSE_MANAGER:0000^License Manager^1";
    var RawItems = roleDetails.Split(',').Select(x=> x.Split('^'));

    var Items1 = RawItems.Select(x=> x.ElementAt(0));       
    var Items2 = RawItems.Select(x=> x.ElementAt(1));
    var Items3 = RawItems.Select(x=> x.ElementAt(2));
    var Items4 = RawItems.Select(x=> x.ElementAt(3));

【讨论】:

  • @Jamiec 为什么会这样?
  • RawItems.Select - 枚举整个列表一次。 x.Take 枚举 n 该列表的元素。 x.Skip 再次枚举列表中的n 元素。所以。许多。隐含的。循环。
  • 例如,您可以刚刚完成x.ElementAt(2)。消除所有skip/Take 的疯狂。
  • @Jamiec:扩展您的论点,String.Split 返回一个 array,可以更轻松地通过索引访问它。 x.Skip(1).Take(1) 等于 x[1]。使用skip and take不必要地使代码复杂化。 (编辑:还没有看到你的第二条评论,同样的论点也适用于x.ElementAt(1),尽管这已经比跳过和接受要少得多)
  • @Flater 因此我的回答:)
【解决方案5】:

如果您不喜欢 LINQ 解决方案,这里有一个没有的解决方案:

var result = new string[4];
var i = 0;
foreach(var line in roleDetails.Split(','))
    foreach(var piece in line.Split('^'))
        result[i++ % 4] += (i <= 4 ? "" : ",") + piece;

基本上,您在逗号和插入符号上进行拆分,并使用一个计数器告诉我们要连接到哪个数组元素以及是否使用逗号分隔符。

如果您的初始字符串比本示例中的大得多,请考虑首先创建一个 StringBuilders 数组,因为它们在连接时性能更好:

var stringBuilders = new StringBuilder[4];
var result = new string[4];
var i = 0;
for (var i = 0; i < 4; i++)
    stringBuilders[i] = new StringBuilder();
foreach(var line in roleDetails.Split(','))
    foreach(var piece in line.Split('^'))
        stringBuilders[i++ % 4].Append((i <= 4 ? "" : ",") + piece);
foreach (var stringBuilder in stringBuilders)
    result[i++ % 4] = stringBuilder.ToString();

【讨论】:

    【解决方案6】:

    另一种 LINQ 解决方案。但不如@Pavel 干净:

    string a = "", b = "", c = "", d = "";
    roleDetails.Split(',').ToList().ForEach(x =>
            {
                a += x.Split('^')[0] + ',';
                b += x.Split('^')[1] + ',';
                c += x.Split('^')[2] + ',';
                d += x.Split('^')[3] + ',';
            });
    MessageBox.Show(a.Trim(','));
    MessageBox.Show(b.Trim(','));
    MessageBox.Show(c.Trim(','));
    MessageBox.Show(d.Trim(','));
    

    输出:

    a = 09A880C2-8732-408C-BA09-4AD6F0A65CE9,24B11B23-1669-403F-A24D-74CE72DFD42A,6A4A6543-DB9F-46F2-B3C9-62D69D28A0B6,76B3B165-0BB4-4E3E-B61F-0C0292342CE2,B3C0CE51-00EE-4A0A-B208-98653E21AE11,CBA225BC-680C-4627-A4F6-BED401682816,D80CF5CF-CB6E-4424-9D8F-E29F96EBD4C9,E0275936-FBBB-4775-97D3-9A7D19D3E1B4
    b = Z:WB:SELECT_DOWNLOAD:0000,Z:WB:TRAINING_SUBSCRIBER:0000,Z:WB:LIC_MGR_HOME_REDL:0000,Account Admin,Z:WB:1BENTLEY_ISA_ADMIN:0000,ReadOnly,Z:WB:MY_SELECT_CD:0000,Z:WB:LICENSE_MANAGER:0000
    c = Product Delivery - Download,Training Subscriber,License Manager - Home use,Account Admin,Co-Administrator,ReadOnly,Product Delivery - DVD,License Manager
    d = 1,1,1,1,1,1,1,1
    

    【讨论】:

    • 为什么会被否决?它产生 OP 正在寻找的结果
    • 这可行,但它是一种非常糟糕的技术。这将循环和解析字符串太多次。由于所有的字符串操作,它会非常慢。
    • 你是对的 :) 但 OP 最初并没有要求更好的 性能。否则我什至不会首先提出 LINQ 解决方案!
    • linq 非常快......这不是 linq。 .ToList().ForEach(...) 单独导致第一个 .Split(...) 的数组结果循环两次。并且您的 a,b,c,d 行每个都重新解析 x
    • 哦,好吧。适当指出的点。感谢您花时间解释:]
    【解决方案7】:

    相当干净和快速......

    var sets = new[]
    {
        new List<string>(),
        new List<string>(),
        new List<string>(),
        new List<string>(),
    };
    
    foreach (var role in roleDetails.Split(','))
    {
        var details = role.Split('^');
        sets[0].Add(details[0]);
        sets[1].Add(details[1]);
        sets[2].Add(details[2]);
        sets[3].Add(details[3]);
    }
    
    var lines = sets.Select(set => string.Join(",", set)).ToArray();
    

    ...有点难以理解,并没有真正节省任何性能...

    var ret = roleDetails.Split(',')
            .Aggregate(seed: new { SBS = new[] { new StringBuilder(), new StringBuilder(),
                                                 new StringBuilder(), new StringBuilder(), },
                                   Start = true },
    
            func: (seed, role) =>
            {
                var details = role.Split('^');
    
                if (seed.Start)
                {
                    seed.SBS[0].Append(details[0]);
                    seed.SBS[1].Append(details[1]);
                    seed.SBS[2].Append(details[2]);
                    seed.SBS[3].Append(details[3]);
    
                    return new
                    {
                        seed.SBS,
                        Start = false,
                    };
                }
                else
                {
                    seed.SBS[0].Append(',').Append(details[0]);
                    seed.SBS[1].Append(',').Append(details[1]);
                    seed.SBS[2].Append(',').Append(details[2]);
                    seed.SBS[3].Append(',').Append(details[3]);
    
                    return seed;
                }
            },
            resultSelector: result => result.SBS.Select(sb => sb.ToString()).ToArray()
            );
    

    【讨论】:

      【解决方案8】:

      你可以在这里使用Tuple

      var roles = roleDetails.Split(',')
                  .Select(x => x.Split('^'))
                  .Where(x=>x.Length==4)
                  .Select(x=> 
                   new Tuple<string, string, string, string>(x[0], x[1], x[2], x[3]))
                  .ToList();
      
                  var item1 = string.Join(",", roles.Select(x=>x.Item1).ToArray());     
                  var item2 = string.Join(",", roles.Select(x => x.Item2).ToArray());
                  var item3 = string.Join(",", roles.Select(x => x.Item3).ToArray());
                  var item4 = string.Join(",", roles.Select(x => x.Item4).ToArray());
      

      【讨论】:

        【解决方案9】:

        您的尝试试图在一行中完成所有操作,这使您更难理解正在发生的事情。

        您已经在使用所需的所有工具(Select()Split())。如果您通过将所有内容分成单独的代码行来使代码更具可读性,那么找到您的方式会变得更加容易:

        //Your data string
        string myDataString = "..."; 
        
        //Your data string, separated into a list of rows (each row is a string)
        var myDataRows = myDataString.Split(',');
        
        //Your data string, separated into a list of rows (each row is a STRING ARRAY)
        var myDataRowsAsStringArrays = myDataRows.Select(row => row.Split('^'))
        

        现在,您需要做的就是检索正确的数据。

        var firstColumnValues  = myDataRowsAsStringArrays.Select(row => row[0]);
        var secondColumnValues = myDataRowsAsStringArrays.Select(row => row[1]);
        var thirdColumnValues  = myDataRowsAsStringArrays.Select(row => row[2]);
        var fourthColumnValues = myDataRowsAsStringArrays.Select(row => row[3]);
        

        如果您愿意,您可以将这些值连接成一个逗号分隔的字符串:

        var firstColumnString  =  String.Join(", ", firstColumnValues);
        var secondColumnString =  String.Join(", ", secondColumnValues);
        var thirdColumnString  =  String.Join(", ", thirdColumnValues);
        var fourthColumnString =  String.Join(", ", fourthColumnValues);
        

        【讨论】:

        • 如果我能就需要改进的地方获得一些反馈,我愿意改进我的答案。
        猜你喜欢
        • 2022-11-22
        • 1970-01-01
        • 1970-01-01
        • 2018-11-13
        • 2022-11-16
        • 2018-06-12
        • 1970-01-01
        • 2021-10-22
        • 2019-06-29
        相关资源
        最近更新 更多