【问题标题】:Separating values in list when it decrease and increase当列表减少和增加时分离列表中的值
【发布时间】:2013-10-10 03:13:48
【问题描述】:

这就是我想做的。

我在一个列表中有大量的数字,但它有一个增加或减少的序列。

例如, 100 200 300 400 500 600 500 400 300 200 100 500 700 800 900

假设这些值存储在列表或数组中。我怎样才能将这些分成多个数组或由序列组成的列表。

例如,列表1:100 200 300 400 500 600 清单 2:500 400 300 200 100 清单 3:500 700 800 900

这就是我所做的。我被卡住了。

for (int i = 0; i < p.Count - 1; i++)
{
    double v = p.ElementAt(i);
    if (initialP > v)
    {
        if (low == 1)
        {
            sep.Add(sep_index);
            low = 0;
        }
        else
        {

        }
        high = 1;
    }

    if (initialP < v)
    {
        if (high == 1)
        {
            sep.Add(sep_index);
            high = 0;
        }
        low = 1;
    }
    initialP = v;
    sep_index++;

    if (i == p.Count - 2)
    {
        sep.Add(sep_index);
    }
}

【问题讨论】:

  • 制作列表列表,解析列表然后循环遍历,如果列表中的下一项与当前模式匹配,则将其添加到解析列表,否则将解析列表添加到列表列表并将其“重置”到新列表
  • 这是一个有趣的问题
  • 天啊..我已经尝试了很长一段时间了 Sayse..我只是想不通..可以提供一个小的书面算法吗?非常感谢..

标签: c# arrays algorithm list multidimensional-array


【解决方案1】:

按照 cmets 中的建议,您应该使用列表列表,并且在循环时在排序方向发生切换时使用新列表:

编辑:已修复以考虑相等的数字和严格的比较。

    public static List<List<int>> GetLists(int[] nums, bool strict) { 
        List<List<int>> lists = new List<List<int>>();
        List<int> list = new List<int>();
        lists.Add(list);
        list.AddRange(nums.Take(1));
        if (nums.Length <= 1) {
            return lists;
        }
        if (strict && nums[0] == nums[1]) {
            list = new List<int>();
            lists.Add(list);
            list.Add(nums[1]);
        }
        else
            list.Add(nums[1]);


        if (nums.Length == 2)
        {
            return lists;
        }

        int direction = Math.Sign(nums[2] - nums[1]);
        for (int i = 2; i < nums.Length; i++) {
            int d = Math.Sign(nums[i] - nums[i - 1]);
            if ((d == direction && (d != 0 || !strict))
                    || (d != 0 && strict)
                    || (Math.Abs(d + direction) == 1 && !strict))
            {
                list.Add(nums[i]);
                if (d != 0 && direction == 0) direction = d;
            }
            else
            {
                direction = d;
                list = new List<int>();
                list.Add(nums[i]);
                lists.Add(list);
            }
        }
        return lists;
    }

    static void Main(string[] args)
    {
        int[] nums = new int[] { 2, 2, 2, 1, 1, 3, 3, 4, 4 };
        var lists = GetLists(nums, false);
        foreach (var list in lists) {
            foreach (var item in list)
            {
                Console.Write(item + " ");
            }
            Console.WriteLine();
        }
        /*
         * Prints:
         * 2 2 2 1 1
         * 3 3 4 4
         * */
    }

【讨论】:

  • 完美!!非常感谢...帮助很大!!
  • 抱歉,但是 "GetLists(new int[] {3, 2, 1});"似乎是测试失败:“[[3, 2, 1]]” 是预期的,而“[[1]]” 是实际得到的。
  • @DmitryBychenko 抱歉,第一个版本运行良好。然后我将其更改为不测试 Length == 0 和 Length == 1 和 Length == 2(查看过去的编辑)我现在修复它。
  • 再次抱歉,但是 "GetList(new int[] { 2, 2, 2, 1, 1, 3, 3, 4, 4});"似乎是另一个测试失败:输出是 "[[2, 2, 2, 1, 1], [3], [3], [4], [4]]" 其中第一个子列表接受相等的项目 (" 2", "1") 而其他子列表没有 ("3", "4")。应为“[[2, 2, 2, 1, 1], [3, 3, 4, 4]]”。
【解决方案2】:

推导,或自旋。如果它是正的——一个方向。否则——另一个。 使用旋转,它将向您显示方向(向上或向下):(n+1/n)。当自旋发生变化时,将元素存储在列表中。

【讨论】:

    【解决方案3】:

    可能的解决方案:

        public static IList<IList<int>> UpDownSeparator(IEnumerable<int> value) {
          if (Object.ReferenceEquals(null, value))
            throw new ArgumentNullException("value");
    
          List<IList<int>> result = new List<IList<int>>();
    
          List<int> current = new List<int>();
          result.Add(current);
    
          // +1 - asceding, -1 - descending, 0 - to be determined later
          int direction = 0;
    
          foreach(int item in value) {
            if (direction == 0) {
              if (current.Count > 0) {
                if (item > current[current.Count - 1])
                  direction = 1;
                else if (item < current[current.Count - 1])
                  direction = -1;
              }
    
              current.Add(item);
            }
            else if (direction < 0) {
              if (item > current[current.Count - 1]) {
                direction = 1;
                current = new List<int>() { item };
                result.Add(current);
              }
              else
                current.Add(item);
            }
            else {
              if (item < current[current.Count - 1]) {
                direction = -1;
                current = new List<int>() { item };
                result.Add(current);
              }
              else
                current.Add(item);
            }
          }
    
          return result;
        }
    
    ....
    
      List<int> list = new List<int>() { 100, 200, 300, 400, 500, 600, 500, 400, 300, 200, 100, 500, 700, 800, 900};
    
      // [[100, 200, 300, 400, 500, 600], [500, 400, 300, 200, 100], [500, 700, 800, 900]]
      IList<IList<int>> result = UpDownSeparator(list);
    

    【讨论】:

      【解决方案4】:

      我会这样做:

      private static List<int[]> SplitOnDirection(int[] input)
      {
          List<int[]> output = new List<int[]>();
          List<int> currentList = new List<int>();
      
          bool? isRaising = null;
          int? previousNumber = null;
      
          foreach (int number in input)
          {
              // do we have a previous value?
              if (previousNumber.HasValue)
              {
                  // only if the number is different, then we have to check the direction.
                  if (number != previousNumber.Value)
                  {
                      bool isHigherNumber = (number > previousNumber.Value);
      
                      // do we already know if we start with raise/lowering
                      if (isRaising.HasValue)
                      {
                          // if we have a higher number and we're not raising, change direction.
                          if (isHigherNumber != isRaising.Value)
                          {
                              // We changed direction..
                              output.Add(currentList.ToArray());
                              currentList = new List<int>();
                          }
                      }
      
                      isRaising = isHigherNumber;
                  }
              }
      
              previousNumber = number;
              currentList.Add(number);
          }
          // if we didn't changed direction, we should 'flush' these.
          if (currentList.Count > 0)
              output.Add(currentList.ToArray());
      
          return output;
      }
      
      int[] input = new int[] { 100, 200, 300, 400, 500, 600, 500, 400, 300, 200, 100, 500, 700, 800, 900 };
      
      List<int[]> output = SplitOnDirection(input);
      

      【讨论】:

      • 抱歉,测试调用“SplitOnDirection(new int[] { 2, 2, 2, 1, 1, 3, 3, 4, 4});"返回奇怪的“[[2, 2, 2, 1, 1] [3] [3] [4] [4]]”:对于第一个子列表,相等的值(“2”,“1”)是可以的,而至于其他(“3”,“4”)不是
      • 结果是对的。 2,2,2,1,1 正在下降,但 3,3,4,4 正在上升。它给出了两个列表结果。可能只是错过了我在if (number != previousNumber.Value) 上的更新,所以现在已经修复了。
      【解决方案5】:

      花了大约 20 分钟,但我会在下面做这样的事情。使用 Java,我确信可以使用其他语言语法轻松编写。

      Input
      1, 1, 1, -1, 2, 3, 4, 4, 4, 5, 6, 5, 4, 4, 3, 3, 6, 6, 2, 1, 5, 7, 8, 9
      Output
      1 1 1 -1 
      2 3 4 4 4 5 6 
      5 4 4 3 3 
      6 6 
      2 1 
      5 7 8 9 
      

      代码

      public static void main(String[] args) {
          int[] input = new int[]{1, 1, 1, -1, 2, 3, 4, 4, 4, 5, 6, 5, 4, 4, 3, 3, 6, 6, 2, 1, 5, 7, 8, 9};
          List<List<Integer>> lists = split(input);
          for (List<Integer> list : lists) {
              for (Integer integer : list) {
                  System.out.print(integer+" ");
              }
              System.out.println("");
          }
      }
      
      public static List<List<Integer>> split(int[] input) {
          List<List<Integer>> listOfList = new ArrayList<List<Integer>>();
          if(input.length >= 1) {
              List<Integer> list = newList(listOfList, input[0]);
              Order lastO = null;
              int last = input[0];
      
              for (int i = 1; i < input.length; i++) {
                  Order currentO = Order.getOrder(input[i], last);
                  boolean samePattern = Order.sameDirection(currentO, lastO);
      
                  if(lastO == null || samePattern) {
                      list.add(input[i]);
                  } else {
                      list = newList(listOfList, input[i]);
                      lastO = null;
                  }
      
                  if(currentO != Order.Equal){
                      lastO = currentO;
                  }
                  last = input[i];
              }
          } 
          return listOfList;
      }
      
      private static List<Integer> newList(List<List<Integer>> listOfList, int element) {
          List<Integer> list = new ArrayList<Integer>();
          listOfList.add(list);
          list.add(element);
          return list;
      }
      
      
      private static enum Order {
          Less, High, Equal;
      
          public static Order getOrder(int first, int second) {
              return first > second ? High : first < second ? Less : Equal;  
          }
      
          public static boolean sameDirection(Order current, Order last) {
              if(last == Order.Less && (current == Order.Less  || current == Order.Equal)) {
                  return true;
              } else if(last == Order.High && (current == Order.High  || current == Order.Equal)) {
                  return true;
              }
              return false;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2016-05-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-11
        • 2012-05-30
        • 1970-01-01
        相关资源
        最近更新 更多