按后续负数的数组(先前)数组

时间:2016-10-20 11:51:49

标签: c# arrays algorithm

我试图处理(在C#中)带有一些数字数据的大型数据文件。给定一个整数数组,如何对其进行拆分/分组,以便在下一个 n (两个或更多)为负数的情况下对先前的 n 元素进行分组。例如,在下面的数组中,应使用两个或多个连续的负数作为提示,以对相同数量的先前元素进行分组:

public Customer findByCustomerId(int custId){

    String sql = "SELECT * FROM CUSTOMER WHERE CUST_ID = ?";

    Customer customer = (Customer)getJdbcTemplate().queryForObject(
            sql, new Object[] { custId }, new CustomerRowMapper());

    return customer;
}

输出:

0 
1
4 
-99
-99
-99
1 
2 
7 
9 
-99
-99
3 
6 
8 
-99
-99
5 

将这样的数据数组处理成新的分组集合的最快,最有效的方法是什么?

2 个答案:

答案 0 :(得分:1)

我可能会尝试整个流程,保持“当前非负数”的缓冲区和负数的计数。这里有一些似乎有效的代码......我希望它至少非常高效。我会从那开始,如果它对你来说效率不高,请研究一下原因。

(如果你想把整个数组放在内存中,你不需要建立numbersToEmit列表,因为你可以只修改索引。但是考虑到重用了一个列表,我我希望这没关系。)

using System;
using System.Linq;
using System.Collections.Generic;

class Program
{
    static void Main(string[] args)
    {
        int[] input = { 0, 1, 4, -99, -99, -99, 1, 
                2, 7, 9, -99, -99, 3, 6, 8, -99, -99, 5 };
        foreach (var group in GroupByNegativeCounts(input))
        {
            Console.WriteLine(string.Join(", ", group));
        }
    }

    static IEnumerable<int[]> GroupByNegativeCounts(IEnumerable<int> input)
    {
        List<int> numbersToEmit = new List<int>();
        int negativeCount = 0;
        foreach (var value in input)
        {
            // We never emit anything when we see a negative number
            if (value < 0)                
            {
                negativeCount++;
            }
            else
            {
                // We emit numbers if we've previously seen negative
                // numbers, and then we see a non-negative one.
                if (negativeCount > 0)
                {
                    int singles = Math.Max(numbersToEmit.Count - negativeCount, 0);
                    foreach (var single in numbersToEmit.Take(singles))
                    {
                        yield return new[] { single };
                    }
                    if (singles != numbersToEmit.Count)
                    {
                        yield return numbersToEmit.Skip(singles).ToArray();
                    }
                    negativeCount = 0;
                    numbersToEmit.Clear();
                }
                numbersToEmit.Add(value);
            }
        }
        // Emit anything we've got left at the end.
        foreach (var single in numbersToEmit)
        {
            yield return new[] { single };
        }
    }
}

答案 1 :(得分:1)

Here's my solution, I tried to make it as simple as possible :)

    List<int> input = new List<int>() { 0, 1, 4, -99, -99, -99, 1, 2, 7, 9, -99, -99, 3, 6, 8, -99, -99, 5 };
    List<int> reverse_input = input.Reverse<int>().ToList();    //reverse list for easier reading
    List<List<int>> grouped_input = new List<List<int>>();      //output variable

    List<int> leading_positives;
    int leading_negative_count;

    while (reverse_input.Any())
    {
        //Get the amount of leading negatives and remove them from the reversed list
        leading_negative_count = reverse_input.TakeWhile(num => num < 0).Count();
        reverse_input = reverse_input.Skip(leading_negative_count).ToList();

        //get and store leading positives and remove them from the reversed list
        leading_positives = reverse_input.TakeWhile(num => num >= 0).ToList();
        reverse_input = reverse_input.Skip(leading_positives.Count).ToList();

        //take an amount of positives equal to the amount of previously found negatives and add them as a separate list to the output
        grouped_input.Add(leading_positives.Take(leading_negative_count).Reverse().ToList());

        //for each remaining positive add it as an individual into the output
        leading_positives.Skip(leading_negative_count).ToList().ForEach(num => grouped_input.Add(new List<int>() { num }));               
    }

//output display       
grouped_input.Reverse<List<int>>().ToList().ForEach(lst => Console.WriteLine(string.Join(",", lst)));