【问题标题】:How can I compare a string to char[] with no memory allocations?如何在没有内存分配的情况下将字符串与 char[] 进行比较?
【发布时间】:2013-03-01 22:30:26
【问题描述】:

在本例中,我必须将数组转换为字符串才能使用内置的String.Compare 方法。

char[] array = {'a','b','c'};
string s = "abc";

// here is the extra string allocation
var arrayString = new String(array);

var compareResult = String.Compare(s, arrayString);

有没有一种简单的方法可以在不分配额外字符串的情况下将字符串与 char 数组进行比较?

注意:这里我需要比较语义 "[a] 32 位有符号整数,表示两个比较数之间的词法关系。"

小于零 -> strA 小于 strB。

零 -> strA 等于 strB。

大于零 -> strA 大于 strB。

(我在循环中进行此比较,并且通过额外的字符串分配(25-100MB,基于我的输入大小)产生了很多额外的垃圾_。

我想我最终可能会弄脏自己的手,自己编写代码。

【问题讨论】:

  • 可以遍历字符串——它实现了IEnumerable<Char>
  • 你能发布你的比较代码吗?我不明白你为什么在比较循环中生成更多变量???只需在 char 数组上使用 for each 循环

标签: c# .net


【解决方案1】:

试试这个

int len = Math.Min(array.Length, s.Length);
for (int i = 0; i < len; i++) {
    if (s[i] < array[i]) return -1;
    if (s[i] > array[i]) return +1;
}
return s.Length.Compare(array.Length);

【讨论】:

  • 但是你为leni分配空间! (笑话,+1)
  • 正是我想要的。谢谢。
【解决方案2】:

字符串实现IEnumerable&lt;Char&gt;,所以你可以循环它们:

for(int i = 0; i < s.Length; i++)
{
   // Do comparisons of  s.Chars[i] with array[i] as wanted
}

以上将避免额外的字符串分配(并假设字符串长度将与字符数组长度相同或更大)。

【讨论】:

  • IEnumerable&lt;char&gt; 仅与 foreach/enumerator 访问有关;该示例使用 indexer 访问,而不是枚举器。作为副作用,这确实否定了@Richard 的观察。但这意味着答案的第一行与示例无关。
【解决方案3】:

你可以写一个扩展方法:

public static int Compare(this String str, char[] chars)
{
    for (int i = 0; i < str.Length; i++)
        if (i == chars.Length)
            return 1;
        else if (str[i] < chars[i])
            return -1;
        else if (str[i] > chars[i])
            return 1;
    if (chars.Length > str.Length)
        return -1;           
    return 0;
}

【讨论】:

  • 错了!如果str = "abc"chars = { 'z' } 然后chars &gt; str。 OP 想要一个词法顺序。
  • 呵呵,没想到词法顺序是这样工作的!我会尽快解决这个问题!
【解决方案4】:

使用 SequentialEqual 怎么样?

char[] array = {'a', 'b', 'c'};
string s = "abc";
bool result = array.SequentialEqual(s);

如果它们相等则结果为真,如果它们不同则为假。

我知道它不会比较数组和字符串,它只检查它们是否相等。其他人已经对这个问题做出了更好的回答。

好的,我的解决方案基于@FlyingStreudel 和@Olivier Jacot-Descombes 的解决方案:

private void button1_Click(object sender, EventArgs e)
{
    char[] array = { 'a', 'b', 'c' };
    string s = "abc";
    s.Compare(array);
}

...

public static class StringUtils
{
    public static int Compare(this String str, char[] chars)
    {
        if (str == null && chars == null) return 0;
        if (str == null) return -1;
        if (chars == null) return 1;
        int max = Math.Min(str.Length, chars.Length);
        for (int i = 0; i < max; i++)
            if (str[i] < chars[i])
                return -1;
            else if (str[i] > chars[i])
                return 1;
        return str.Length.CompareTo(chars.Length);
    }
}

主要区别在于我不会将每个字符的 i 与 chars.Length 进行比较。

希望这对你的探索有所帮助。

【讨论】:

  • 这只会告诉你这些是否相等 - 如果一个比另一个 更大,如 OP 指定的那样。
  • 它会为枚举器分配内存。
  • @OlivierJacot-Descombes 这个想法只是为了避免将整个数组复制到一个新字符串中以便能够进行比较,而不是在根本不使用任何内存的情况下进行编程。他正在寻找 O(1) 内存占用而不是 O(n)。
  • @Servy:另一点是您是在堆栈上还是在堆上分配内存。在堆上创建数百万个对象会为 GC 产生大量工作。
  • @OlivierJacot-Descombes 关键是这不会根据数组的大小分配任何内容。每个序列只有一个枚举器,而不是每个字符分配的。
猜你喜欢
  • 1970-01-01
  • 2012-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-27
  • 1970-01-01
相关资源
最近更新 更多