私は を持っています。List<CreditCard>
クレジット カードのプロパティは ですCreditCardNumber
。これは文字列です。残念ながら、それは1234 1234 1234 1234
、または1234123412341234
であり、どちらも同じ数です。
これらの重複したアイテムを調べて削除する必要があります。誰か助けてくれませんか?
using System.Linq;
public List<string> GetUniqueCardNumbers(List<string> cardNumbers)
{
// First replace the spaces with empty strings
return cardNumbers.Select(cc => cc.Replace(" ", ""))
.Distinct()
.ToList();
}
最適なオプションは、入力時にカード番号からスペースを削除して、クリーニング操作を 1 回実行するだけで済むようにすることです。
public class CreditCard: IComparable<CreditCard>
{
string creditCardNumberClean;
string creditCardNumberOriginal;
public string CreditCardNumber
{
get
{
return this.creditCardNumberOriginal;
}
set
{
this.creditCardNumberOriginal = value;
this.creditCardNumberClean = value.Replace(" ", "");
}
}
public CreditCard(string creditCardNumber)
{
this.CreditCardNumber = creditCardNumber;
}
public int CompareTo(CreditCard other)
{
return this.creditCardNumberClean.CompareTo(other.creditCardNumberClean);
}
}
しかし、それが不可能な場合は、基本的に、比較の前にすべてのスペースを削除するために番号を変更するだけで、カード番号に対して文字列比較を実行する必要があります。
class Program
{
public static void Main(string[] args)
{
List<string> list = new List<string>(new string[]{"1234 1234 1234 1234", "1234123412341234","9999 9999 9999 9999"});
SortedSet<string> set = new SortedSet<string>(list, new CreditCardNoComparer());
foreach (string s in set)
{
Console.WriteLine(s);
}
Console.ReadKey();
}
}
public class CreditCardNoComparer : IComparer<string>
{
public int Compare(string x, string y)
{
return x.Replace(" ", "").CompareTo(y.Replace(" ", ""));
}
}
編集
//version using overridden GetHashCode and Equals methods as per @lazyberezovsky's comments
public class CreditCard
{
long creditCardNumberClean; //given the card number is numeric this is the most efficient way of storing it
string creditCardNumberOriginal;
public string CreditCardNumber
{
get
{
return this.creditCardNumberOriginal;
}
set
{
this.creditCardNumberOriginal = value;
this.creditCardNumberClean = long.Parse(value.Replace(" ", ""));
}
}
public CreditCard(string creditCardNumber)
{
this.CreditCardNumber = creditCardNumber;
}
public override bool Equals(object obj)
{
CreditCard other = obj as CreditCard;
return
other == null
? false
: this.creditCardNumberClean.Equals(other.creditCardNumberClean);
}
public override int GetHashCode()
{
return this.creditCardNumberClean.GetHashCode();
}
}
任意の文字列から数字のみを抽出できます。この場合、空白文字を空の文字に置き換えることしかできません。より複雑な文字列形式の場合は、次のコードを使用して数字のみを取得できます。この回答を確認できます:数字のみを取得
string justNumbers = new String("asd123 f3 4.34-3 ".Where(Char.IsDigit).ToArray());
次に、あなたの数字だけがありCreditCardNumber
、重複した値を検索できます。
IEnumerable<CreditCard> distinctCards = cards
.Select(card => new {
card,
ccn = card.CreditCardNumber.Replace(" ", string.Empty)
})
.GroupBy(x => x.ccn)
.Select(g => g.First().card) //group has at least 1 member, so First() is safe
//.ToList() ???
Distinct();
空白を削除する独自EqualityComparer
のものを作成し、重複を削除するために使用できます。CreditCard
Enumerable.Distinct
public class CardComparer : IEqualityComparer<CreditCard>
{
private readonly Regex re = new Regex(@"\s+");
public bool Equals(CreditCard x, CreditCard y)
{
return re.Replace(x.Number, "") == re.Replace(y.Number, "");
}
public int GetHashCode(CreditCard obj)
{
return re.Replace(obj.Number, "").GetHashCode();
}
}
それで:
IEnumerable<CreditCard> unique = sourceList.Distinct(new CardComparer());
まず、「等しい」とは何かを判断する必要があります。埋め込まれたスペースを削除するのと同じくらい簡単な場合は、空白を削除して を呼び出す以前のソリューションのいずれかを使用できますDistinct
。それ以外の場合は、等値比較子を作成してDistinct オーバーロードに渡す必要があります。