【问题标题】:Bitwise OR on strings for large strings in c#c#中大字符串的按位或字符串
【发布时间】:2016-06-19 23:48:18
【问题描述】:

我有两个长度相等 (

我应该如何处理这个问题。我正在使用 c#。

当我考虑显而易见的解决方案时,读取每个字符并应用 OR |在他们身上,我必须处理 apx,250000 个字符串,每个字符串的长度为 500。这会影响我的表现。

性能是我最关心的问题。

提前致谢!

【问题讨论】:

  • 你试过什么?最明显的解决方案有什么问题(读取每个字符,或将其写入新字符串)?
  • 您可以使用 StringBuilder 和循环。看我的回答。
  • 首先你是如何得到字符串的?如果你追求性能,最好考虑一下是否可以使用其他数据结构
  • @Rotem,是的,我做了最明显的事情,但我关心的是性能。
  • @KooKiz,我从源文件中读取它作为字符串。

标签: c# string bitwise-or


【解决方案1】:

这是最快的方法:

string x="";
string y="";
StringBuilder sb = new StringBuilder(x.Length);
for (int i = 0; i < x.Length;i++ )
{
    sb.Append(x[i] == '1' || y[i] == '1' ? '1' : '0');
}
string result = sb.ToString();

【讨论】:

  • 感谢您提供代码 sn-p。我可以用“|”吗逻辑或是否有机会?
  • @Reddy 逻辑或 ||是为布尔值而不是字符定义的
  • @Reddy | 仅用于布尔值和按位数字,不适用于字符和字符串。
  • @M.kazemAkhgary 除了这个答案+字符串的并行处理。
  • @Sakura 这取决于输入是否包含更多0 或更多1。如果两个字符串都为零,则使用|| 会更慢。
【解决方案2】:

既然提到速度是一个重要因素,最好使用按位运算。

看看ASCII table

  • 字符'0'0x30,或二进制的00110000
  • 字符'1'0x31,或二进制的00110001

只有字符的最后一位不同。因此,我们可以肯定地说,对字符本身执行按位或运算将产生正确的字符。

我们可以做的另一件重要的事情是优化速度是使用StringBuilder,初始化为我们字符串的初始容量。或者更好:尽管我们必须确保StringBuilder 有足够的容量,但我们可以将StringBuilder 重复用于多个操作。

考虑到这些优化,我们可以制作这个方法:

string BinaryStringBitwiseOR(string a, string b, StringBuilder stringBuilder = null)
{
    if (a.Length != b.Length)
    {
        throw new ArgumentException("The length of given string parameters didn't match");
    }

    if (stringBuilder == null)
    {
        stringBuilder = new StringBuilder(a.Length);
    }
    else
    {
        stringBuilder.Clear().EnsureCapacity(a.Length);
    }

    for (int i = 0; i < a.Length; i++)
    {
        stringBuilder.Append((char)(a[i] | b[i]));
    }
    return stringBuilder.ToString();
}

请注意,这适用于您希望对字符串执行的所有按位操作,您只需修改 | 运算符。

【讨论】:

  • A string 是 Unicode/UTF-16 代码单元 (char) 的计数序列,因此您最好查看 Unicode table 并了解 UTF-16 编码而不是查看在 ASCII 表中。在这种情况下,Unicode 代码点“0”和“1”各有一个 UTF-16 代码单元,U+0030 -> 0x0030 和 U+0031 -> 0x0031。
【解决方案3】:

我发现这比所有提议的解决方案都要快。它结合了@Gediminas 和@Sakura 的答案中的元素,但使用预初始化的char[] 而不是StringBuilder

虽然StringBuilder 在内存管理方面效率很高,但每个Append 操作都需要对标记进行一些记账,并且执行的操作比仅对数组的索引要多。

string x = ...
string y = ...
char[] c = new char[x.Length];
for (int i = 0; i < x.Length; i++)
{
    c[i] = (char)(x[i] | y[i]);
}
string result = new string(c);

【讨论】:

  • 是的,这是最好的。不安全的代码呢?可以更快吗?
  • 根据我的测试,如果我们最终不需要转换回string,不安全的代码会更快。否则它会更慢,因为未管理 -> 托管转换为 string 占用了一半的时间。
  • 从提问者的评论中,他从文件中读取了字符串。对于特定情况,他可以直接读取字节数组并逐位执行。
【解决方案4】:

我有两个长度相等的字符串(1 和 0)(

您可以编写一个自定义逻辑 OR 运算符或函数,它将两个字符作为输入并产生结果(例如,如果输入字符中的至少一个为 '1',则返回 '1' - 否则返回 '0')。将此函数应用于字符串中的每个字符。

你也可以看看这个方法。您首先需要将每个字符转换为布尔值(例如,'1' 对应于 true),在两个布尔值之间执行 OR 运算,将结果转换回字符 '0' 或 '1' - 取决于逻辑 OR 的结果是否为 false或分别为真。然后只需将此操作的每个结果附加到彼此。

【讨论】:

  • 我必须处理 apx,250000 个字符串,每个字符串的长度为 500。这会影响我的表现。
  • @Reddy 您应该编辑您的原始问题并包含该信息 - 知道您需要性能非常重要,并且您将运行 250,000 次而不是一次。
  • @Reddy 你能改变你的数据结构吗?如果可以并且想要性能,请不要使用字符串。使用带有位掩码算法的int 数组或使用BitArray
【解决方案5】:

您可以使用Linq 查询压缩然后聚合结果:

var a = "110010";    
var b = "001110";  
var result = a.Zip(b, (i, j) => i == '1' || j == '1' ? '1' : '0')
              .Select(i => i + "").Aggregate((i, j) => i + j);

基本上,Zip 扩展方法采用两个序列并对两个序列的每个对应元素应用一个操作。然后我使用Selectchar 转换为String 最后我aggregate 将字符串序列(“0”和“1”)的结果转换为字符串。

【讨论】:

  • 按位需要速度。这种方式很慢。
  • @Sakura 您需要对字符的字节级别进行按位操作吗?好吧,我不确定它是否会直截了当,因为您必须处理 Unicode/Ascii/UTF-8、UTF-16 等……您是否使用特定的格式/文化?
  • 我们是否对字符串进行了某种位操作??
  • @Reddy 好吧,我们不能对整个字符串执行按位操作,但我们可以对字符串的每个字符执行操作。每个字符由一个或多个字节表示(取决于编码 - ASCII/Unicode,然后是 UTF-8、UTF-16 等...)。所以理论上我们可以对字符的字节执行按位操作。但是我们应该知道确切的编码,所以我们可以只屏蔽代表字符的相关位(其他位用于编码)。
猜你喜欢
  • 1970-01-01
  • 2012-03-03
  • 1970-01-01
  • 2011-07-29
  • 2013-02-06
  • 2016-03-05
  • 2014-10-22
  • 2017-01-14
  • 1970-01-01
相关资源
最近更新 更多