我有一个Message
的列表以及它们的项目长度为size
,this.Size = JsonConvert.SerializeObject(Data).Length;
。
public class Data
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Message
{
public Data Data { get; set; }
public int Size { get; set; }
public Message(Data Data)
{
this.Data = Data;
this.Size = JsonConvert.SerializeObject(Data).Length;
}
}
现在我有下面的数据集,我想将列表分成多个列表,每个列表只能是50个字节(例如)。
注意-以50为例,我的实际大小为1 MB,没有任何一条消息大于1MB
我在下面尝试过,但是如何计算总大小并按组块大小分组
.GroupBy(x => x.ItemSize / chunkSize)
还是其他方式?
var messages = new List<Message>
{
new Message(new Data{ Id=100, Name="N100"}),
new Message(new Data{ Id=1100, Name="N1100"}),
new Message(new Data{ Id=11100, Name="N11100"}),
new Message(new Data{ Id=111100, Name="N111100"}),
new Message(new Data{ Id=1111100, Name="N1111100"})
};
int chunkSize = 50;
var X = messages
.Select(x => new { ItemSize = x.Size, Value = x })
.GroupBy(x => x.ItemSize / chunkSize)
.Select(x => x.Select(v => v.Value).ToList())
.ToList();
答案 0 :(得分:6)
这可能有用。.前提是懒惰地迭代IEnumerable<Message>
和yields
和IEnumerable<List<Message>>
(Message
的子列表)的累积量大于chunk
大小
public static IEnumerable<List<Message>> Split(this IEnumerable<Message> source, int chunk)
{
var list = new List<Message>();
var accum = 0;
foreach (var message in source)
{
accum += message.Size;
if (accum > chunk)
{
yield return list;
list = new List<Message>();
accum = message.Size;
}
list.Add(message);
}
// Return last result if any
if (list.Any()) yield return list;
}
用法
var sublists = messages.Split(50);
这是一个有用的方法,因此我使它通用并且更适合于库。它包括完整性检查,如果size
大于chunk
public static IEnumerable<List<T>> Buffer<T>(this IEnumerable<T> source, int chunk, Func<T, long> selector)
{
// safety first
if (source == null) throw new ArgumentNullException(nameof(source));
var list = new List<T>();
long accum = 0;
foreach (var item in source)
{
var size = selector(item);
// sanity check
if (size > chunk) throw new InvalidOperationException("Selector size cant be greater than chunk size");
// Return chunk
if ((accum += size) > chunk)
{
yield return list;
list = new List<T>();
accum = size;
}
list.Add(item); // always need to add the current
}
// Return any partial result
if (list.Any()) yield return list;
}
用法
var results = messages.Buffer(50, x => x.Size)