0
votes

This is what I would like to do.

I have huge number of number in a list, but it has a sequence of either increasing or decreasing.

Such as, 100 200 300 400 500 600 500 400 300 200 100 500 700 800 900

Lets say this values are stored in a list or maybe an array. How could I separate these to multiple arrays or list consisting of the sequence.

Such as, List 1: 100 200 300 400 500 600 List 2 :500 400 300 200 100 List 3:500 700 800 900

This is what I have done. I am stuck.

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);
    }
}
5
Make a list of lists, and a parsing list then loop through, if the next item in the list matches the current pattern, add it to the parsing list, otherwise add the parsing list to the list of lists and "reset it" to a new listSayse
this is kind of a fun problemJonesopolis
oh god.. i have been trying that for quite some time Sayse.. i just cant figure it out.. can provide a small written algorithm for it? thx alot..Sàtz ÑÖÑït

5 Answers

2
votes

As suggested in the comments, you should use a list of of lists and while looping use a new list when there is a switch in the direction of the sort:

EDIT: Fixed to take into account equal numbers and strict comparaisons.

    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
         * */
    }
0
votes

Derivation, or spin. If it is positive -- one direction. Otherwise -- another. Use spin, which will show you direction (up or down): (n+1/n). When spin changes, then store elements in a list.

0
votes

Possible solution:

    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);
0
votes

I would do something like this:

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);
0
votes

Took around 20 min, but I would do something like this below. Using Java, I am sure could easily be written using other language syntax.

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 

Code

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;
    }
}