代码之家  ›  专栏  ›  技术社区  ›  J_PT

C#通用列表更新项目

  •  1
  • J_PT  · 技术社区  · 6 年前

    List<T> 我需要更新列表中的对象属性。

    高效/更快 列表<T> 会随着列表的增长而变慢 不是进行更新的最有效的集合。

    那就悲哀了,最好是:

    • 扫描列表索引,直到找到匹配的对象,然后更新对象的属性?
    • 如果我有一个集合,让我们IEnumerable,我想将IEnumerable更新到列表中,什么是最好的方法。

    存根代码示例:

    public class Product
    {
        public int ProductId { get; set; }
        public string ProductName { get; set; }
        public string Category { get; set; }
    }
    
    public class ProductRepository
    {
        List<Product> product = Product.GetProduct();
        public void UpdateProducts(IEnumerable<Product> updatedProduct)
        {
        }
        public void UpdateProduct(Product updatedProduct)
        {
        }
    }
    
    3 回复  |  直到 6 年前
        1
  •  1
  •   Mrinal Kamboj    6 年前

    您的用例正在更新 List<T>

    架构如下:

    public class Product
    {
        public int ProductId { get; set; }
        public string ProductName { get; set; }
        public string Category { get; set; }
    }
    

    Product 包含主键,这意味着 产品 对象可以唯一标识,并且没有重复项,并且每个更新目标都有一个唯一的记录?

    如果 ,那么最好安排 列表<T> 以…的形式 Dictionary<int,T> ,这意味着 IEnumerable<T> O(1) 时间复杂性,这意味着所有的更新都可以根据系统的大小来完成

    万一 产品 列表<T> O(logN)

    既然 IEnumerable<T> 相对较小,例如M,因此总体时间复杂度为 O(M*logN) ,其中M比N小得多,可以忽略不计。

    列表<T> 支持二进制搜索API,它提供了元素索引,然后可以用它来更新对象的相关索引,检查 example 在这里

    我认为,对于如此多的记录,最好的选择是并行处理和二进制搜索

    列表<T> 进入 List<T>[] MoreLinq 批处理Api,在这里您可以使用 Environment.ProcessorCount 然后创建 IEnumerable<IEnumerable<T>> 具体如下:

    var enumerableList = List<T>.Batch(Environment.ProcessorCount).ToList();
    

    另一种方法是遵循自定义代码:

    public static class MyExtensions
    {
        // data - List<T>
        // dataCount - Calculate once and pass to avoid accessing the property everytime
        // Size of Partition, which can be function of number of processors
        public static List<T>[] SplitList<T>(this List<T> data, int dataCount, int partitionSize)
        {
            int remainderData;    
            var fullPartition = Math.DivRem(dataCount, partitionSize, out remainderData);    
            var listArray = new List<T>[fullPartition];    
            var beginIndex = 0;
    
            for (var partitionCounter = 0; partitionCounter < fullPartition; partitionCounter++)
            {
                if (partitionCounter == fullPartition - 1)
                    listArray[partitionCounter] = data.GetRange(beginIndex, partitionSize + remainderData);
                else
                    listArray[partitionCounter] = data.GetRange(beginIndex, partitionSize);    
                beginIndex += partitionSize;
            }    
            return listArray;
        }
    }
    

    Task[] ,每个 Task 为每个元素指定 列表<T> ,在 列表<T>[] 在上面生成,然后对每个子分区进行二进制搜索。虽然它是重复的,但会使用并行处理和二进制搜索的力量。每个 任务 可以启动,然后我们可以使用 Task.WaitAll(taskArray) 等待任务处理完成

    Dictionary<int,T>[] 因此,使用并行处理,这将是最快的。

    列表<T>[] 列表<T> 可以使用Linq完成 Aggregation SelectMany 具体如下:

    List<T>[] splitListArray = Fetch splitListArray;
    
    // Process  splitListArray
    
    var finalList = splitListArray.SelectMany(obj => obj).ToList()
    

    Parallel.ForEach 以及线程安全的数据结构,如 ConcurrentBag<T> 或者可能是 ConcurrentDictionary<int,T> 如果要替换完整的对象,但如果其属性更新,则 并行循环 在内部使用类似于我上面建议的range partitioner

    上述解决方案在理想情况下取决于您的用例,您应该能够使用组合来实现最佳可能的结果。让我知道,如果你需要具体的例子

        2
  •  2
  •   Jamie Lupton    6 年前

    如果你想快速查找,可以考虑使用字典而不是列表。在您的情况下,它将是产品Id(我假设它是唯一的)。 Dictionary MSDN

    例如:

    public class ProductRepository
        {
            Dictionary<int, Product> products = Product.GetProduct();
            public void UpdateProducts(IEnumerable<Product> updatedProducts)
            {
                foreach(var productToUpdate in updatedProducts)
                {
                    UpdateProduct(productToUpdate);
                }
    
                ///update code here...
            }
            public void UpdateProduct(Product productToUpdate)
            {
                // get the product with ID 1234 
                if(products.ContainsKey(productToUpdate.ProductId))
                {
                    var product = products[productToUpdate.ProductId];
                    ///update code here...
                    product.ProductName = productToUpdate.ProductName;
                }
                else
                {
                    //add code or throw exception if you want here.
                    products.Add(productToUpdate.ProductId, productToUpdate);
                }
            }
        }
    
        3
  •  1
  •   ΩmegaMan    6 年前

    效率到底是什么?

    除非有上千个项目在执行foreach、for或任何其他类型的循环操作,否则它们很可能只在千秒内显示差异。真正地因此,你浪费了更多的时间(程序员每小时XX美元的成本比最终用户的成本)去寻找这个问题 最好的

    所以,如果你有成千上万条记录,我建议你用 Parallel.Foreach 方法,可以处理更多的记录,以节省时间和线程的开销。


    如果记录计数大于100,则表示正在使用数据库。如果涉及到一个数据库,写一个更新存储过程并停止;我很难写一个一次性的程序来做 特定更新 这可以在上述数据库中以更简单的方式完成。