我试图处理(在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
将这样的数据数组处理成新的分组集合的最快,最有效的方法是什么?
答案 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)));