为了账号安全,请及时绑定邮箱和手机立即绑定

如何在不使用额外内存的情况下连接列表?

如何在不使用额外内存的情况下连接列表?

C#
回首忆惘然 2022-07-10 10:34:03
你如何在不加倍内存的情况下连接巨大的列表?考虑以下代码段: Console.WriteLine($"Initial memory size: {Process.GetCurrentProcess().WorkingSet64 /1024 /1024} MB"); int[] a = Enumerable.Range(0, 1000 * 1024 * 1024 / 4).ToArray(); int[] b = Enumerable.Range(0, 1000 * 1024 * 1024 / 4).ToArray(); Console.WriteLine($"Memory size after lists initialization: {Process.GetCurrentProcess().WorkingSet64 / 1024 / 1024} MB"); List<int> concat = new List<int>(); concat.AddRange(a.Skip(500 * 1024 * 1024 / 4)); concat.AddRange(b.Skip(500 * 1024 * 1024 / 4)); Console.WriteLine($"Memory size after lists concatenation: {Process.GetCurrentProcess().WorkingSet64 / 1024 / 1024} MB");输出是:Initial memory size: 12 MBMemory size after lists initialization: 2014 MBMemory size after lists concatenation: 4039 MB我想在连接后将内存使用量保持在 2014 MB,而不修改 a 和 b。
查看完整描述

3 回答

?
拉风的咖菲猫

TA贡献1995条经验 获得超2个赞

如果你需要一个List<int>,你不能这样做。AList<int>总是直接包含它的数据,所以当你有两个(比如说)100 个元素的数组和一个通过连接这两个元素创建的列表时,你已经有了 400 个独立元素。你无法改变这一点。

您正在寻找的是一种创建数据的独立副本的方法。如果您只是在搜索它(就像评论中的声音一样),您可以使用使用IEnumerable<int>LINQ 创建的:

IEnumerable<int> concat = a.Concat(b);

如果您需要类似 anIReadOnlyList<T>甚至 an 的东西IList<T>,您可以自己实现这些接口以在多个数组上创建适配器 - 但您可能需要自己编写。如果你能坚持IEnumerable<T>使用 LINQ,使用 LINQ 会简单很多。


查看完整回答
反对 回复 2022-07-10
?
慕仙森

TA贡献1827条经验 获得超8个赞

我可以建议您进行一些优化:


IEnumerable<int>在不调用 ToArray() 方法的情况下初始化 a 和 b


int size = 1000 * 1024 * 1024 / 4;

IEnumerable<int> a = Enumerable.Range(0, size);

IEnumerable<int> b = Enumerable.Range(0, size);

用已知容量初始化 concat


List<int> concat = new List<int>(size);

结果我得到以下输出:


Initial memory size: 12 MB

Memory size after lists initialization: 13 MB

Memory size after lists concatenation: 1021 MB

如果您只想串联搜索某些内容,则可以这样做而无需额外分配:


IEnumerable<int> concat = a.Skip(500 * 1024 * 1024 / 4).Concat(b.Skip(500 * 1024 * 1024 / 4));

int search = concat.Count(i => i % 2 == 0);

Console.WriteLine($"Search result: {search}");


查看完整回答
反对 回复 2022-07-10
?
人到中年有点甜

TA贡献1895条经验 获得超7个赞

他们是执着的。我只需要连接它们,进行一些搜索,然后处理连接列表


如果您只需要进行一些搜索,为什么首先需要连接?分别搜索两个数组。


您正在搜索的内容可能会桥接两个数组。如果是这种情况,为了让事情变得更容易并且不支付内存价格,只需实现一个模拟操作但实际上不执行它的包装器:


sealed class Concatenated<T>:

    IReadOnlyList<T>

{

    public static Concatenated<T> 

        Concatenate<T>(

            IReadOnlyList<T> first,

            IReadOnlyList<T> second)

        => new ConcatenatedArray<T>(first, second);


    private readonly IReadOnlyList<T>

       first, second;


    private Concatenated(

        IReadOnlyList<T> first,

        IReadOnlyList<T> second)

    {

        this.first = first;

        this.second = second;

    }


    public T this[int index] 

        => index < first.Length ? 

           first[index]: 

           second[index - first.Length];


    public int Count => first.Length + second.Length;


    public IEnumerator<T> GetEnumerator()

    {

        foreach (var f in first)

            yield return f;


        foreach (var s in second)

            yield return s;

    }


    IEnumerator IEnumerable.GetEnumerator()

        => GetEnumerator();

}


查看完整回答
反对 回复 2022-07-10
  • 3 回答
  • 0 关注
  • 95 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信