与此类似的问题:Combination of List<List<int>>
然而,改组使得这非常重要,IMO需要一个完全不同的解决方案。我很高兴被证明是错的,但这并不像改组结果那么容易,因为结果列表不适合内存:
我需要合并3个 LARGE 列表:
List<int> A = new List<int> {1, 2, 3, ...};
List<int> B = new List<int> {4, 5, 6, ...};
List<int> C = new List<int> {7, 8, 9, ...};
输出是新的List<object> { {1, 4, 7}, {1, 4, 8}, ... }
但是,我需要对结果列表进行洗牌。如果它们在组合时仍然是图案化的,那么对每个单独的列表进行混洗将是不够的,并且虽然3个列表将适合于存储器,但是所有3个列表的组合将不会。一个混洗的索引列表显然太大而无法存储在内存中。
我已经尝试了许多不同的方法,但我找不到一种方法来随机化订单而不先加载每个项目。这可能吗?谢谢!
答案 0 :(得分:0)
如果所有列表都具有相同的大小:
var aShuffle = new List<int>(A.Count);
aShuffle.AddRange(A.Shuffle());
var bShuffle = new List<int>(B.Count);
bShuffle.AddRange(B.Shuffle());
var cShuffle = new List<int>(C.Count);
cShuffle.AddRange(C.Shuffle());
List<Trio> trios = new List<Trio>(aShuffle.Count);
for (int i = 0; i < aShuffle.Count; i++)
{
trios.Add(new Trio { Value1 = aShuffle[i], Value2 = bShuffle[i], Value3 = cShuffle[i] });
}
使用此结构:
public struct Trio
{
public int Value1 { get; set; }
public int Value2 { get; set; }
public int Value3 { get; set; }
}
我已经使用此扩展程序来收集(Fisher-Yates)集合:
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source)
{
return source.Shuffle(new Random());
}
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random rng)
{
if (source == null) throw new ArgumentNullException("source");
if (rng == null) throw new ArgumentNullException("rng");
return source.ShuffleIterator(rng);
}
private static IEnumerable<T> ShuffleIterator<T>(
this IEnumerable<T> source, Random rng)
{
List<T> buffer = source.ToList();
for (int i = 0; i < buffer.Count; i++)
{
int j = rng.Next(i, buffer.Count);
yield return buffer[j];
buffer[j] = buffer[i];
}
}
Value1: 3 Value2: 5 Value3: 8
Value1: 1 Value2: 6 Value3: 9
Value1: 6 Value2: 4 Value3: 7
Value1: 2 Value2: 8 Value3: 33
答案 1 :(得分:0)
您是否尝试过使用Union LINQ-Extension?
您可以使用它来统一列表,然后随机播放结果:)
答案 2 :(得分:0)
扩展我的评论...
首先,确定你不能在物理内存中进行这种随机播放。如果您的项目少于UInt32.MaxValue
,您仍然可以use managed arrays。另外,您只需要为每件商品存储int
(或可能long
),而不是商品本身。
那么,你有这么多的项目你不能在内存中计算它们吗?
首先为文件中的每个项目存储一个数字。
using (var f = File.Create("shuffle.bin"))
{
var length = A.Count * B.Count * C.Count;
f.SetLength(length * sizeof(long));
for (long i = 0; i < length; i++)
{
var bytes = BitConverter.GetBytes(i);
f.Write(bytes, 0, sizeof(long));
}
}
彻底改变这个文件需要花费很长时间。因此,我们可以根据需要随时将一个条目随机播出。提取一个数字不需要太长时间。
using (var f = File.Open("shuffle.bin", FileMode.Open))
{
// Calculate how many numbers are left in the file.
long itemCount = f.Length / sizeof(long);
if (itemCount == 0)
{
// We have used all the items - create another file, or throw
// an exception, or whatever you want.
}
// You need an equivalent of `Random.Next(int max)` here that works on `long`s.
long index = NextLong(itemCount);
// Read out the number you've shuffled out.
f.Seek(index * sizeof(long), SeekOrigin.Begin);
var rtnBytes = new byte[sizeof(long)];
f.Read(rtnBytes, 0, sizeof(long));
// Read out the last number.
f.Seek((itemCount - 1) * sizeof(long), SeekOrigin.Begin);
var rplcBytes = new byte[sizeof(long)];
f.Read(rplcBytes, 0, sizeof(long));
// Replace the shuffled-out number with the last number.
f.Seek(index * sizeof(long), SeekOrigin.Begin);
f.Write(rplcBytes, 0, sizeof(long));
// Trim the now-duplicate last number off the end of the file.
f.SetLength((itemCount - 1) * sizeof(long));
// Get the long and do with it what you want.
long rtnLong = BitConverter.ToInt64(rtnBytes, 0);
}
然后,您可以将此long
转换为三个索引,如下所示:
int indexA = (int)(rtnLong % (long)A.Count);
rtnLong /= a.Count;
int indexB = (int)(rtnLong % (long)B.Count);
rtnLong /= b.Count;
int indexC = (int)rtnLong;