比较一组三个字符串与另一个字符串

时间:2015-12-03 19:16:55

标签: c# string string-comparison

我正在列出一组独特的"一组3个字符串"从某些数据来看,如果3个字符串组合在一起就会变成一个集合,我的列表中只能有唯一的集合。

  1. A,B,C
  2. B,C,d
  3. D,E,F等
  4. 如果列表中不存在集合,我会继续添加集合,因此如果我在一起遇到这三个字符串{A,B,C},我就不会再将其放入列表中。 所以我有2个问题。第二个答案实际上取决于第一个答案。

    1. 如何存储这组3个字符串,使用List或数组或连接它们还是其他任何东西? (我可以将它添加到词典中以记录他们的计数,但以后会记录)
    2. 如何将一组3个字符串与另一个字符串进行比较,无论其顺序如何,显然取决于所使用的结构?我想知道一个正确的解决方案,而不是天真地做一切!
    3. 我正在使用C#。

4 个答案:

答案 0 :(得分:3)

  1. 数组或列表是存储数据的最佳选择,因为正如评论中提到的wentimo,连接它们意味着您正在丢失您可能需要的数据。为了窃取他的榜样," ab" " cd" ef"连接在一起与" abcd"相同" E"和" f"连接,但不应被视为等效集。

  2. 为了比较它们,我会按字母顺序排列列表,然后按顺序比较每个值。这照顾了值的顺序并不重要的事实。 伪代码示例可能如下所示:

    Compare(List<string> a, List<string> b)
    {
        a.Sort();
        b.Sort();
        if(a.Length == b.Length)
        {
            for(int i = 0; i < a.Length; i++)
            {
                if(a[i] != b[i])
                {
                    return false;
                }
            }
            return true;
        }
        else
        {
            return false;
        }
    }
    
  3. 更新

    既然您在评论中表示性能是一个非常重要的考虑因素,因为您可能有数百万个这样的集合需要比较,并且您不会在集合中有重复的元素,这里是我的代码的更优化版本,请注意,我不再需要对两个列表进行排序,这将节省执行此函数的相当多的时间。

    Compare(List<string> a, List<string> b)
    {
        if(a.Length == b.Length)
        {
            for(int i = 0; i < a.Length; i++)
            {
                if(!b.Contains(a[i]))
                {
                    return false;
                }
            }
            return true;
        }
        else
        {
            return false;
        }
    }
    

    DrewJordan使用散列表的方法仍然可能不是我的方法,因为它只需对每组三个进行排序,然后可以比我的方法更快地与现有集进行比较。

答案 1 :(得分:1)

如果您不需要在集合中包含重复元素,则最好的方法是使用HashSet。听起来每组3都有3个独特的元素;如果实际上是这种情况,我会将HashSet方法与您已经解决的连接组合起来,即对元素进行排序,与某些分隔符组合,然后将连接的元素添加到HashSet中,这将防止重复发生在HashSet中。第一名。

如果您的三个可能有重复的元素,那么Kevin's approach就是您要为每个元素做的事情。通过为每组三个使用HashSets列表,您可能会获得更好的性能,但是只有三个元素,为可能数百万个集合的每个元素创建哈希的开销似乎表现得更差,然后只迭代它们一次。

答案 2 :(得分:0)

这是一个简单的字符串包装器:

/// The wrapper for three strings
public class StringTriplet
{

    private List<string> Store;

    // accessors to three source strings:
    public string A { get; private set; }
    public string B { get; private set; }
    public string C { get; private set; }

    // constructor (need to feel internal storage)
    public StringTriplet(string a, string b, string c)
    {
        this.Store = new List<string>();
        this.Store.Add(a);
        this.Store.Add(b);
        this.Store.Add(c);
        // sort is reqiured, cause later we don't want to compare all strings each other
        this.Store.Sort();
        this.A = a;
        this.B = b;
        this.C = c;
    }


    // additional method. you could add IComparable declaration to the entire class, but it is not necessary in your task...
    public int CompareTo(StringTriplet obj)
    {
        if (null == obj)
            return -1;

        int cmp;
        cmp = this.Store.Count.CompareTo(obj.Store.Count);
        if (0 != cmp)
            return cmp;

        for (int i = 0; i < this.Store.Count; i++)
        {
            if (null == this.Store[i])
                return 1;

            cmp = this.Store[i].CompareTo(obj.Store[i]);
            if ( 0 != cmp )
                return cmp;
        }

        return 0;
    }

    // additional method. it is a good practice : override both 'Equals' and 'GetHashCode'. See below..
    override public bool Equals(object obj)
    {
        if (! (obj is StringTriplet))
            return false;
        var t = obj as StringTriplet;
        return ( 0 == this.CompareTo(t));
    }

    // necessary method . it will be implicitly used on adding values to the HashSet
    public override int GetHashCode()
    {
        int res = 0;
        for (int i = 0; i < this.Store.Count; i++)
            res = res ^ (null == this.Store[i] ? 0 : this.Store[i].GetHashCode()) ^ i;

        return res;
    }
}

现在您可以创建hashset并添加值:

var t = new HashSet<StringTriplet> ();

t.Add (new StringTriplet ("a", "b", "c"));
t.Add (new StringTriplet ("a", "b1", "c"));
t.Add (new StringTriplet ("a", "b", "c"));  // dup
t.Add (new StringTriplet ("a", "c", "b"));  // dup
t.Add (new StringTriplet ("1", "2", "3"));
t.Add (new StringTriplet ("1", "2", "4"));
t.Add (new StringTriplet ("3", "2", "1"));

foreach (var s in t) {
    Console.WriteLine (s.A + " " + s.B + " " + s.C);
}
return 0;

答案 3 :(得分:0)

您可以继承List<String>并覆盖Equals()GetHashCode()方法:

public class StringList : List<String>
{
    public override bool Equals(object obj)
    {
        StringList other = obj as StringList;
        if (other == null) return false;
        return this.All(x => other.Contains(x));
    }
    public override int GetHashCode()
    {
        unchecked
        {
            int hash = 19;
            foreach (String s in this)
            {
                hash = hash + s.GetHashCode() * 31;
            }
            return hash;
        }
    }
}

现在,您可以使用HashSet<StringList>仅存储唯一集