我有{1,2,3,5,8,9,10}之类的整数列表,我需要以下结果 [1,3],[5,5],[8,10]
我使用命令式样式编写了解决方案,但我想要一个与函数式编程一致的解决方案。
我的必要解决方案:
public static List<ContinuousNotificationSegment> ConvertToNotificationSegment(this List<NotificationDTO> input)
{
var sortedNotificationList = input.Select(n => n.ID).ToList();
sortedNotificationList = sortedNotificationList.OrderBy(n => n).ToList();
List<ContinuousNotificationSegment> continuousSegments = new List<ContinuousNotificationSegment>();
long continuousSegmentStart = 0, continuousSegmentEnd = 0;
for (int i = 0; i < sortedNotificationList.Count; i++)
{
if (IsContinuous(sortedNotificationList[i], ((i + 1) < sortedNotificationList.Count ? sortedNotificationList[i + 1] : -999)))
{
continuousSegmentStart = continuousSegmentStart == 0 ? sortedNotificationList[i] : continuousSegmentStart;
}
else
{
continuousSegmentEnd = sortedNotificationList[i];
continuousSegments.Add(new ContinuousNotificationSegment
{
MinNotificationId = continuousSegmentStart == 0 ? continuousSegmentEnd : continuousSegmentStart,
MaxNotificationId = continuousSegmentEnd
});
continuousSegmentStart = 0;
}
}
return continuousSegments;
}
private static bool IsContinuous(long prevValue, long nextValue)
{
return nextValue - prevValue == 1;
}
答案 0 :(得分:2)
答案 1 :(得分:1)
您可以通过首先排序数字列表,然后选择当前数字和前一个数字之间的差值大于1时递增的数字和分组ID来实现。然后只对该分组ID进行分组并采取最小和最大数字作为范围。
public static IEnumerable<Tuple<int, int>> Runs(this IEnumerable<int> nums)
{
int? prev = null;
int group = 0;
return nums.OrderBy(n => n)
.Select(
n =>
{
if (prev.HasValue && n - prev.Value > 1) { group++; }
prev = n;
return new { group, num = n };
})
.GroupBy(x => x.group)
.Select(g => new Tuple<int, int>(g.Min(x => x.num), g.Max(x => x.num)));
}
这段代码
var nums = new[] { 1, 2, 3, 5, 7, 8, 9 };
Console.WriteLine(string.Join(";", nums.Runs()));
输出
(1,3);(5,5);(7,9)
答案 2 :(得分:1)
因为我已经被教导在功能上编程它应该看起来像(警告,它是[伪代码]!和[尾递归]!)
GetRanges(input)
if (input == null || input.Count == 0)
return {};
var ranges = {};
GetRangesInternal(ranges, {null, null}, input);
return ranges;
GetRangesInternal(ranges, {initialElement, lastElement}, input) =>
var head = input.Take(1);
var tail = input.Skip(1);
// no first element - prepare new range and move on
if (initialElement == null)
GetRangesInternal(ranges, {head, head}, tail);
return;
// range continued - update it and move on
if (head == lastElement+1)
GetRangesInternal(ranges, {initialElement, head}, tail)
return;
// range stopped - add it to result
ranges.Add({initialElement, lastElement});
GetRangesInternal(ranges, {head, head}, tail);
GetRanges
是入口点
答案 3 :(得分:0)
我能想出的最紧凑,最清晰的LINQ是:
var intList = new List<int> { 1, 2, 3, 5, 8, 9, 10 };
var agg = intList.Aggregate(new List<List<int>> { new List<int>() }, (i, j) =>
{
if (!i.Last().Any() || i.Last().Last() + 1 == j)
i.Last().Add(j);
else
i.Add(new List<int> { j });
return i;
}).Select(i => new List<int> { i.First(), i.Last() });
结果完全如问题所述。