【问题标题】:Split a list of files into multiple smaller lists based on file size in c#在c#中根据文件大小将文件列表拆分为多个较小的列表
【发布时间】:2015-07-16 14:10:09
【问题描述】:

我正在编写一个方法,它将获取大量文件并将它们拆分为包含相等总磁盘空间的较小列表。例如。一个包含 1 个 100kb 文件的列表,另一个包含 100 个 1kb 文件的列表。

我拥有的代码执行以下操作。如果列表中的所有文件总计超过 500kb,我想将此列表拆分为更小的列表。这意味着如果我的总数为 600kb,我将有 2 个列表。我想在每个列表中添加 300kb(或尽可能接近)的文件。

我编写的代码可以很好地做到这一点,但有一种常见的场景会搞砸。如果我有 99 个文件。 99 个是 1kb,最后一个文件是 400kb。此代码将来回向每个列表添加 1 个文件,直到两个列表都有 49 个文件,每个列表中的每个列表为 49kb,但现在最终文件很大,这意味着 1 个列表将是 49kb,另一个是 449kb。我需要一种聪明的方法来划分文件,以便 400kb 的文件最终出现在一个列表中。

int listcount = (int)Math.Ceiling(totalsize / listlimit); //500kb

    List<string>[] lists = new List<string>[listcount];
    double[] memorytotals = new double[listcount]; // this array will keep track of what the file size total is in each of the arrays.

    foreach(string file in filelist)
    {
        double size = new FileInfo(file).Length;

        int pos = 0;
        for (int i = 0; i < memorytotals.Length; i++)
    {
        if (memorytotals[i] < memorytotals[pos]) { pos = i; }
    }
       if(size > memorytotals[pos])
        {
            //get the next smallest array that is not pos
            int pos2 = 0;
            for (int i = 0; i < memorytotals.Length; i++)
            {
                if (memorytotals[i] < memorytotals[pos2] && pos2 != pos) 
                { 
                    pos2 = i; 
                }
            }

            //if moving all contents of the smallest array into the second smallest array make for a smaller size than just putting the larger file directly into the smaller array than do it.
            double newlistTotal = memorytotals[pos] + memorytotals[pos2];
            if(newlistTotal < size)
            {
                lists[pos2].AddRange(lists[pos]);
                //empty the list in order to add the new larger file to this list.
                lists[pos].Clear();
            }
        }
        lists[pos].Add(file);
    }

【问题讨论】:

  • 您可能需要执行一种两遍方案:仅获取文件名和大小的列表,然后从那里分解它们,然后将它们添加到拆分列表中。.
  • 这听起来像是packing problem 的变体——你可能想研究通用打包算法
  • 也许您可以对所有文件进行排序,其中第一个文件最重。然后运行你的算法,我认为它会起作用。
  • 问题不简单,比如400,200,290,47,63,totalSize小于1000,但是如果你的split size是500就必须用3个list来保存
  • 嗯,包装问题正是我的问题,非常感谢!我开始怀疑实现均匀大小的列表所需的处理是否会通过处理均匀大小的列表来超过性能提升。我会进一步研究这个问题,看看我是否能想出一种方法来改进我目前的方法,而无需大量额外的处理

标签: c# list


【解决方案1】:

这不是最佳解决方案,但至少它将文件分成不同的列表,大小相同。代码可以做很多改进,只是第一种方法。

我根据文件大小对文件进行排序,然后开始将它们添加到列表中,检查是否永远不会超过限制。

int listcount = (int)Math.Ceiling(totalsize / listlimit); //500kb
            List<FileInfo> fileInfoList = new List<FileInfo>();

            List<string>[] lists = new List<string>[listcount];

            double[] memorytotals = new double[listcount]; // this array will keep track of what the file size total is in each of the arrays.

            foreach (string file in filelist)
            {
                fileInfoList.Add(new FileInfo(file));         // Add all the FileInfo to a list to order it                      
            }

            fileInfoList.OrderBy(r => r.Length);


            foreach (FileInfo fileInfo in fileInfoList)
            {
                double size = fileInfo.Length;

                // flag for only add a file one time
                bool flag = true;


                for (int j = 0; j < memorytotals.Length; j++)
                {

                    // check if the file fits in the list
                    if (memorytotals[j] + size < listcount && flag)
                    {
                        memorytotals[j] = memorytotals[j] + size;
                        lists[j].Add(fileInfo.FullName);
                        flag = false;
                    }
                }
            }

【讨论】:

  • 这个解决方案效果很好。我不想浪费大量的处理来完美地制作列表,所以这解决了我遇到的问题并且不会花费大量的处理来完成
【解决方案2】:

我写了一个打包文件的方法,我用int替换FileInfo,这样测试起来更方便,当然不是很好的实现

static List<List<int>> SplitFileWithLimitSize(List<int> totalSizes, int limitSize)
{
    List<List<int>> resultList = new List<List<int>>();//the result packet
    List<int> tmp = new List<int>();
    int reduceSize = limitSize;
    while (true)
    {
        var maxSize = 0;
        var filters = totalSizes.Where(x => x <= reduceSize);//to fiter the possible size
        if (filters.Any())
        {
            maxSize = filters.Max();//get max size
        }
        if (maxSize == 0)
        {//there is no size got success ,so add the tmp to resultList,and reinit the parameters
            resultList.Add(tmp);
            tmp = new List<int>();
            reduceSize = limitSize;
            continue;
        }
        reduceSize = reduceSize - maxSize;
        totalSizes.Remove(maxSize);
        tmp.Add(maxSize);
        if (totalSizes.Count == 0)
        {//if there is nothing reduce in totalSizes,tmp to resultList,and  break the loop
            resultList.Add(tmp);
            break;
        }
    }
    //resultList.ForEach(x =>
    //{
    //    Console.WriteLine("Pack:" + string.Join(" ", x));
    //});
    return resultList;
}

测试方法是

var totalSizes = new List<int>() { 400, 200, 290, 47, 63 };
var limitSize = 500;
SplitFileWithLimitSize(totalSizes, limitSize);//there will 3 packet in list
Console.WriteLine("#################");
totalSizes = new List<int>() { 400, 200, 290, 100, 10 };
SplitFileWithLimitSize(totalSizes, limitSize);//there will 2 packet in list

【讨论】:

  • 列表 ?
猜你喜欢
  • 1970-01-01
  • 2020-05-05
  • 2012-07-12
  • 2019-04-30
  • 1970-01-01
  • 1970-01-01
  • 2019-09-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多