首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >获取int集合的可能范围

获取int集合的可能范围
EN

Stack Overflow用户
提问于 2017-10-15 10:04:19
回答 4查看 110关注 0票数 0

我有一个id (int)列表,如下所示

代码语言:javascript
运行
复制
[1,2,3,5,7,8,11,13,14..]

有没有快速/智能的方法(linq?)来获取所有的id,或者如果可能,获取范围?结果应该类似于[1-3, 5, 7-8, 11, 13-14]

当然,循环和计算int值以获得结果是很容易的,但我相信肯定有更简单的方法来做到这一点。

EN

回答 4

Stack Overflow用户

发布于 2017-10-15 12:15:49

免责声明这在大列表上是非常慢的,你也应该做一个不同的

这应该能起到作用

代码语言:javascript
运行
复制
    static void Main(string[] args)
    {
        //a list with a possible of duplicate
        var theList = (new int[] { 1, 2, 3, 5, 7, 8, 11, 13, 14, 13 }).OrderBy(x => x).ToList();

        var step1 = theList.Select((a, b) =>  theList.Skip(b).TakeWhile((x, y) => a == x || theList[b + y] - 1 == theList[b + y - 1]));

        var step2 = step1.GroupBy(x => x.Last())
                         .Select(x => x.SelectMany(y => y).Distinct())
                         .Select(x => x.Count() > 1 ? string.Format("{0}-{1}", x.First(), x.Last()) : x.First().ToString());


        var result = string.Format("[{0}]", string.Join(", ", step2));

    }
票数 1
EN

Stack Overflow用户

发布于 2017-10-15 11:01:12

使用单一for循环的老式方法。

代码语言:javascript
运行
复制
try
{
     List<int> i = new List<int>() { 1, 2, 3, 5, 7, 8, 11, 13, 14 };
     int istart = i[0];
     bool flag = false;
     // Use StringBuilder
     for(int index = 0;index<i.Count-1;index++)
     {
         if ((i[index] + 1) == i[index + 1])
         {
              flag = true;
              continue;
         }
         else
         {
              if (!flag)
                  Console.Write(istart);
              else
                  Console.Write(istart + "-" + i[index]);

              Console.Write(",");

              flag = false;
              istart = i[index + 1];
          }
      }
      if (istart + 1 == i[i.Count - 1])
          Console.Write(istart + "-" + i[i.Count - 1]);
      else
          Console.WriteLine(istart);
}
catch(Exception ex)
{
       Console.WriteLine(ex.Message);
}
Console.WriteLine();
Console.WriteLine("Done");
Console.Read();

输入List<int> i = new List<int>() { 1, 2, 3, 5, 7, 8, 11, 13, 14 };

输入List<int> i = new List<int>() { 1, 2, 3, 4, 5, 7, 8, 11, 13, 13 };

输入List<int> i = new List<int>() { 1, 4, 5, 7, 8, 9, 2, 13, 15, 17 };

票数 0
EN

Stack Overflow用户

发布于 2017-10-15 11:23:03

有一种linq方法可以做到这一点(如果数字不重复),但我不确定是否更容易:

代码语言:javascript
运行
复制
int last = -1;
int rank = 0;
IEnumerable<string> grouped = arr
    .GroupBy(i =>
    {
        rank += i - last - 1;
        last = i;
        return rank;
    })
    .Select(g => g.Count() == 1 ? g.First().ToString()
                : g.First().ToString() + "-" + g.Last().ToString());

对我来说,这似乎相当复杂,比必要的资源密集型更多,也不灵活。Linq在许多情况下都很好用,但有时它就是不太适合。简单的循环有时是你能得到的最好的:

代码语言:javascript
运行
复制
IEnumerable<string> Group(IEnumerable<int> sortedArr)
{
    using (var en = sortedArr.GetEnumerator())
    {
        if (!en.MoveNext())
        {
            yield break;
        }
        int first = en.Current;
        int last = first;
        int count = 1;

        while (true)
        {
            bool end;
            if ((end = !en.MoveNext()) || en.Current - last > 1)
            {
                if (count == 1)
                {
                    yield return first.ToString();
                }
                //else if (count == 2)
                //{
                //    yield return first.ToString();
                //    yield return last.ToString();
                //}
                else
                {
                    yield return first.ToString() + "-" + last.ToString();
                }
                if (end) { yield break; }
                first = en.Current;
                count = 1;
            }
            else
            {
                ++count;
            }
            last = en.Current;
        }
    }
}

基准测试

让我们测量一下linq在10M阵列上的实际效率:

代码语言:javascript
运行
复制
  simple loop:  328MB, 1.2sec
      my linq:  790MB, 2.7sec 
 Fredous linq:  1100MB, 7days (estimated)

代码:

代码语言:javascript
运行
复制
int size = 10000000;
int[] arr = new int[size];
Random rnd = new Random(1);

arr[0] = 0;
for(int i = 1; i < size; ++i)
{
    if (rnd.Next(100) < 25)
    {
        arr[i] = arr[i - 1] + 2;
    }
    else
    {
        arr[i] = arr[i - 1] + 1;
    }
}         

System.Diagnostics.Stopwatch st = new System.Diagnostics.Stopwatch();
st.Start();
var res = Group(arr).ToList();
st.Stop();

MessageBox.Show(st.ElapsedMilliseconds.ToString());
MessageBox.Show(res.Sum(s => s.Length).ToString());// to be sure the work is done
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46751027

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档