我正在列出一组独特的"一组3个字符串"从某些数据来看,如果3个字符串组合在一起就会变成一个集合,我的列表中只能有唯一的集合。
如果列表中不存在集合,我会继续添加集合,因此如果我在一起遇到这三个字符串{A,B,C},我就不会再将其放入列表中。 所以我有2个问题。第二个答案实际上取决于第一个答案。
我正在使用C#。
答案 0 :(得分:3)
数组或列表是存储数据的最佳选择,因为正如评论中提到的wentimo,连接它们意味着您正在丢失您可能需要的数据。为了窃取他的榜样," ab" " cd" ef"连接在一起与" abcd"相同" E"和" f"连接,但不应被视为等效集。
为了比较它们,我会按字母顺序排列列表,然后按顺序比较每个值。这照顾了值的顺序并不重要的事实。 伪代码示例可能如下所示:
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使用散列表的方法仍然可能不是我的方法,因为它只需对每组三个进行排序,然后可以比我的方法更快地与现有集进行比较。
答案 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>
仅存储唯一集