必要的免责声明:我希望帮助更好地理解Linq,以便我尝试在工作中解决现实问题并使用Linq解决它。这并不意味着我假设Linq比更直接的程序解决方案更好(更快,更少内存,更具可读性等)。如果有的话,我正试图找到关于我的工作的Linq(和功能风格)的边缘。
作为更大的通信协议的一部分,我有一个List<byte[]>
。这些byte[]
的大小可变,每个都代表对某个系统的请求。这些byte[]
必须以与List<>
中相同的顺序发送到另一个系统,但是最好将几个byte[]
请求打包到单个消息中以减少通信开销。消息的有效负载将是单个byte[]
,它是所有单个byte[]
的串联。
byte[]
的这种打包有两个限制。第一个是我们对可以发送的总字节数(maxSendBytes
)有一个上限。第二个是每个单独的请求将生成一些最大长度的可变长度响应。这些响应的最大长度之和不能大于另一个限制(maxReceiveBytes
)。我们可以使用名为LongestResponseLength
的函数来确定响应的最大长度,该函数接受请求的byte[]
。
因此,理想的最终结果是将表示单个请求的一个List<byte[]>
转换为一个List<byte[]>
,其中每个byte[]
是由串联组成的单个消息有效负载一个或多个byte[]
个请求。
这是我的程序解决方案,可以帮助人们理解我正在尝试做的事情:
public static List<byte[]> PackList(List<byte[]> options, int maxSendBytes = 500, int maxReceiveBytes = 1500-200)
{
var payloads = new List<byte[]>(); // each item is an outbound payload to put in a message
var currentPayload = new List<byte>(); // payload we're accumulating on now
var currentExpectedLength = 0; // expected length of response payload
foreach (var option in options)
{
var optionLength = LongestResponseLength(option);
// add to current payload as long as neither limit hit
if (currentPayload.Count + optionLength >= maxSendBytes ||
currentExpectedLength + optionLength >= maxReceiveBytes)
{
payloads.Add(currentPayload.ToArray()); // add the payload to the list of payloads
currentPayload = new List<byte>(); // start a new payload
currentExpectedLength = 0; // "
}
currentPayload.AddRange(option);
currentExpectedLength += optionLength;
}
if (currentPayload.Count > 0)
{
payloads.Add(currentPayload.ToArray());
}
return payloads;
}
有没有更好的方法来表达上述代码?大概。但那不是问题。
答案 0 :(得分:1)
我很失望,如果不依赖于GroupBy
声明中的副作用,我无法解决这个问题,但我认为这符合您的要求:
var rnd = new Random(0);
//make a list of mock messages
var individualMessages = Enumerable
.Range(0, 1000)
.Select(_ => Enumerable
.Range(0, rnd.Next(1,100))
.Select(__ => (byte)rnd.Next(255))
.ToArray())
.ToList();
var maxMessageSize = 1000;
var total = 0;
var groupingNum = 0;
var aggregatedMessages = individualMessages
.GroupBy(x => {
total += x.Length;
if(total > maxMessageSize){
groupingNum++;
total = x.Length;
}
return groupingNum;
})
.Select(x => x.SelectMany(v => v).ToArray())
.ToList();