从C#列表中获取唯一的三位数字邮编

3

我有一个整数列表,它代表着美国邮政编码,我想根据邮政编码前三位获取唯一值。例如,这是我的列表:

10433
30549
10456
54933
60594
30569
30659

My result should contain only:

10433
30549
54933
60594
30659

我列表中不包括以下美国邮政编码:1045630659,因为我已经有了包含 104xx 和 306xx 的邮编。
我真的不知道该如何完成这个任务,虽然看起来不难,但我实在是毫无头绪。我写了一个函数,可以保存唯一的前三位数字,并在每个邮编的末尾添加了两个随机数字。但它并没有奏效,因为我得到了例如 10423 这样的结果,但 10423 并不在我的列表中,而且我没有一个特定的模式来保证所有数字的最后两位都在一个范围内。

2
你已经使用正则表达式进行了标记。这似乎是更适合使用 LINQ 解决的问题。是否允许使用 LINQ,或者实际上需要使用正则表达式? - Chris
2个回答

12

稍微使用一点Linq应该就可以了。如果使用了一个int列表:

var zips = new[] { 10433, 30549, 10456, 54933, 60594, 30569, 30659 };
var results = zips.GroupBy(z => z / 100).Select(g => g.First());

或者,如果使用字符串列表:

var zips = new[] { "10433", "30549", "10456", "54933", "60594", "30569", "30659" };
var results = zips.GroupBy(z => z.Remove(3)).Select(g => g.First());
另一种解决方案是使用自定义的 IEqualityComparer<T>。对于 int 类型:
class ZipComparer : IEqualityComparer<int> {
    public bool Equals(int x, int y) {
        return x / 100 == y / 100;
    }
    public int GetHashCode(int x) {
        return x / 100;
    }
}

对于 字符串

class ZipComparer : IEqualityComparer<string> {
    public bool Equals(string x, string y) {
        return x.Remove(3) == y.Remove(3);
    }
    public int GetHashCode(string x) {
        return x.Remove(3).GetHashCode();
    }
}

然后,要使用它,您只需调用 Distinct 即可:

var result = zips.Distinct(new ZipComparer());

最后,您还可以使用MoreLINQDistinctBy扩展方法(也可在NuGet上获取):

var results = zips.DistinctBy(z => z / 100);
// or
var results = zips.DistinctBy(z => z.Remove(3));

谢谢,你帮我省了很多时间。我会在几分钟内接受答案,因为我现在没法操作。 - icebox19

2
这里的流行答案提供了代码,但并没有解决问题。问题在于你似乎没有算法。所以...
您会如何在纸上解决这个问题?
我想这个过程可能是这样的:
1. 对于每个数字,确定3位数前缀 2. 如果您还没有具有该前缀的邮政编码,请保留该数字 3. 如果您已经有一个具有该前缀的邮政编码,请丢弃该数字
您会如何用代码写出来?
嗯,您需要几件事情:
1. 一个桶来跟踪您找到的前缀和保留的值。 2. 循环遍历所有项目 3. 确定前缀的方法
以下是一种编写此代码的方法(您可以将其转换为使用字符串作为练习):
ICollection<int> GetUniqueZipcodes(int[] zips)
{
    Dictionary<int, int> bucket = new Dictionary<int,int>();
    foreach (var zip in zips)
    {
        int prefix = GetPrefix(zip);
        if(!bucket.ContainsKey(prefix))
        {
            bucket.Add(prefix, zip);
        }
    }
    return bucket.Values;
}

int GetPrefix(int zip)
{
    return zip / 100;
}

简化代码

现在,很多程序员会说:“天哪,这么多行代码,可以简化成一行。”他们是对的。借鉴p.s.w.g的答案,这个代码可以被简化(而且非常易读):

var results = zips.GroupBy(z => z / 100).Select(g => g.First());

那么这是如何工作的呢?zips.GroupBy(z => z/100)进行分桶操作。最终你会得到一个类似下面的组合集合:
{ 
    104: { 10433, 10456 },
    305: { 30549, 30569 },
    549: { 54933 },
    605: { 60594 },
    306: { 30659 }
}

然后我们使用.Select(g => g.First()),它从每个组中取出第一个项目。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接