簡體   English   中英

將一組三個字符串與另一個字符串進行比較

[英]Compare a set of three strings with another

我正在根據一些數據制作一個唯一的“ 3個字符串集”列表,這樣的話,如果3個字符串在一起,它們就會變成一個集合,而我的列表中只能有唯一的集合。

  1. A,B,C
  2. B,C,D
  3. D,E,F等

而且,如果集在列表中尚不存在,我會繼續將其添加到列表中,這樣,如果我遇到這三個字符串{A,B,C},我就不會再將其放入列表中。 所以我有兩個問題 第二個答案的答案實際上取決於第一個答案。

  1. 如何存儲這組3個字符串,使用List或array或連接它們或其他方式? (我也可以將其添加到字典中以記錄其數量,但這供以后使用)
  2. 如何將一組3個字符串與另一個字符串進行比較,無論它們的順序如何,顯然取決於所使用的結構? 我想知道一個適當的解決方案,而不是天真地做!

我正在使用C#。

  1. 數組或列表都是存儲數據的最佳選擇,因為正如gomoimo在評論中所述,將它們串聯意味着您丟失了可能需要的數據。 舉個例子,串聯在一起的“ 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; } } 

更新資料

既然您在評論中說過,性能是一個重要的考慮因素,因為您可能要比較數百萬個這樣的集合,而且集合中不會有重復的元素,這是我代碼的更優化版本,請注意,我沒有不再需要對兩個列表進行排序,這將節省執行該功能的大量時間。

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使用哈希表的方法可能仍然比我的方法好,因為它只需要對三個一組進行排序,然后可以比我的方法快得多地與現有集進行比較。

如果您的集合中不需要重復的元素,則最好的方法可能是使用HashSet 聽起來每組3個元素都有3個唯一元素; 如果確實是這樣,我將結合使用HashSet方法和已經確定的串聯,即對元素進行排序,與一些分隔符結合,然后將串聯的元素添加到HashSet中,這將防止重復出現第一名。

如果您的三個集合中可能有重復的元素,那么Kevin的方法就是每個元素要做的事情。 通過為每個三個集合使用HashSets列表,您可能會獲得更好的性能,但是對於只有三個元素的情況,為潛在的數百萬個集合的每個元素創建哈希的開銷似乎會更糟,然后對其進行一次迭代。

這是一個簡單的字符串包裝器:

/// 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;
    }
}

現在您可以創建哈希集並添加值:

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;

您可以繼承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>僅存儲唯一的集合

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM