我有一系列字母数字邮政编码,看起来像这样:
PostalCodes(0) = "AA000-DD130"
PostalCodes(1) = "DD131-DD150"
PostalCodes(2) = "DD151-EE180"
PostalCodes(3) = "EE300-EE600"
PostalCodes(4) = "EE450-EE700"
PostalCodes(5) = "EE800"
PostalCodes(6) = "EE810"
PostalCodes(7) = "EE811"
PostalCodes(8) = "EE812"
PostalCodes(9) = "EE813"
PostalCodes(10) = "EE814"
PostalCodes(11) = "EE815"
我希望它能够优化到这样的东西:
PostalCodes(0) = "AA000-EE180"
PostalCodes(1) = "EE300-EE700"
PostalCodes(2) = "EE800"
PostalCodes(3) = "EE810-EE815"
正如你所看到的,范围可以重叠或者可能存在间隙,没问题,我只想尽可能地优化(减少)邮政编码。 我已经有一个使用For循环的代码,但我想知道是否有办法使用Linq更快地完成这项任务并提高性能?
我正在使用vb.net。
提前致谢。
答案 0 :(得分:1)
这几乎是这样的:
Dim PostalCodes(11) As String
PostalCodes(0) = "AA000-DD130"
PostalCodes(1) = "DD131-DD150"
PostalCodes(2) = "DD151-EE180"
PostalCodes(3) = "EE300-EE600"
PostalCodes(4) = "EE450-EE700"
PostalCodes(5) = "EE800"
PostalCodes(6) = "EE810"
PostalCodes(7) = "EE811"
PostalCodes(8) = "EE812"
PostalCodes(9) = "EE813"
PostalCodes(10) = "EE814"
PostalCodes(11) = "EE815"
Dim splits = _
PostalCodes _
.Select(Function (x) If(x.Contains("-"), x.Split("-"c), { x, x })) _
.Select(Function (ps) ps.Select(Function (p) New With _
{ _
.Prefix = p.Substring(0, 2), _
.Value = Integer.Parse(p.Substring(2)) _
}).ToArray()) _
.ToArray()
Dim results = _
splits _
.Skip(1) _
.Aggregate( _
splits.Take(1).ToList(), _
Function (a, x)
Dim l = a.Last()
If x(0).Prefix = l(1).Prefix AndAlso x(0).Value <= l(1).Value + 1 Then
a.RemoveAt(a.Count - 1)
a.Add( _
{ _
New With _
{ _
.Prefix = l(0).Prefix, _
.Value = l(0).Value _
}, _
New With _
{ _
.Prefix = l(1).Prefix, _
.Value = x(1).Value _
} _
})
Else
a.Add(x)
End If
Return a
End Function) _
.Select(Function (xs) String.Format("{0}{1:000}-{2}{3:000}", xs(0).Prefix, xs(0).Value, xs(1).Prefix, xs(1).Value)) _
.ToArray()
它给出了:
AA000-DD180 EE300-EE700 EE800-EE800 EE810-EE815
还有一小部分工作要摆脱双"EE800-EE800"
。
答案 1 :(得分:0)
使用扩展方法将范围转换为带有StartPrefix,Start,EndPrefix,End values的元组:
<Extension()>
Public Function RangeToTuple(ByVal strRange As String) As (StartPrefix As String, Start As Integer, EndPrefix As String, [End] As Integer
If strRange.Contains("-") Then
Dim twoRanges = strRange.Split("-")
Dim intRanges = twoRanges.Select(Function(rs) rs.Substring(2).ToInteger()).ToList()
Return (twoRanges(0).Substring(0, 2), intRanges(0), twoRanges(1).Substring(0, 2), intRanges(1))
Else
Dim intRange = strRange.Substring(2).ToInteger()
Return (strRange.Substring(0, 2), intRange, strRange.Substring(0, 2), intRange)
End If
End Function
使用简单的扩展将String转换为Integer:
<Extension()>
Public Function ToInteger(s As String) As Integer
Return Convert.ToInt32(s)
End Function
使用自定义扩展方法,该方法是APL扫描运算符的变体,其作用类似于Aggregate
但返回中间值,并使用ValueTuple
返回原始值和中间计算:< / p>
<Extension()>
Public Iterator Function ScanPair(Of T, TKey)(src As IEnumerable(Of T), seedKey As TKey, combine As Func(Of (Key As TKey, Value As T), T, TKey)) As IEnumerable(Of (Key As TKey, Value As T))
Using srce = src.GetEnumerator()
If srce.MoveNext() Then
Dim prevkv = (seedKey, srce.Current)
While srce.MoveNext()
Yield prevkv
prevkv = (combine(prevkv, srce.Current), srce.Current)
End While
Yield prevkv
End If
End Using
End Function
一种基于谓词分组的扩展方法:
<Extension()>
Public Function GroupByWhile(Of T, TRes)(src As IEnumerable(Of T), test As Func(Of T, T, Boolean), result As Func(Of T, TRes)) As IEnumerable(Of IGrouping(Of Integer, TRes))
Return src.ScanPair(1, Function(kvp, cur) If(test(kvp.Value, cur), kvp.Key, kvp.Key + 1)) _
.GroupBy(Function(kvp) kvp.Key, Function(kvp) result(kvp.Value))
End Function
<Extension()>
Public Function GroupByWhile(Of T)(src As IEnumerable(Of T), test As Func(Of T, T, Boolean)) As IEnumerable(Of IGrouping(Of Integer, T))
Return src.GroupByWhile(test, Function(e) e)
End Function
然后你可以使用LINQ来处理元组:
Dim combinedRanges = input.Select(Function(rs) rs.RangeToTuple()) _
.GroupByWhile(Function(prev, cur) prev.EndPrefix = cur.StartPrefix And cur.Start <= prev.End+1 And prev.End <= cur.End) _
.Select(Function(kvpg) (kvpg.First().StartPrefix, kvpg.First().Start, kvpg.Last().EndPrefix, kvpg.Last().End)) _
.Select(Function(tp) If(tp.Start = tp.End, $"{tp.StartPrefix}{tp.Start}", _
$"{tp.StartPrefix}{tp.Start}-{tp.EndPrefix}{tp.End}"))
注意:写完这个答案之后,我意识到我可以将我的序列分组结构概括为对谓词进行分组,并使其更易于访问。
每条评论转换为VB。