C#按名称中的自然数排序对文件进行排序?

时间:2012-08-22 16:08:08

标签: c#

我在目录中有文件

0-0.jpeg
0-1.jpeg
0-5.jpeg
0-9.jpeg
0-10.jpeg
0-12.jpeg

...

当我加载文件时:

FileInfo[] files = di.GetFiles();

他们的订单错误(他们应该如上所述):

0-0.jpeg
0-1.jpeg
0-10.jpeg
0-12.jpeg
0-5.jpeg
0-9.jpeg

如何解决这个问题?

我试图对它们进行排序,但没办法:

1) Array.Sort(files, (f1, f2) => f1.Name.CompareTo(f2.Name));

2) Array.Sort(files, (x, y) => StringComparer.OrdinalIgnoreCase.Compare(x.Name, y.Name)); 

7 个答案:

答案 0 :(得分:6)

按字母顺序排列,“错误”的订单实际上是正确的。如果你想要按数字排序,那么你需要:

  1. 将文件名转换为数字列表并对其进行排序
  2. 以字母和数字排序相同的方式命名文件(0-001.jpeg和0-030.jpg)
  3. 依赖文件创建时间进行排序(假设文件是​​按顺序创建的)。
  4. 请参阅Sorting Directory.GetFiles()的答案,了解#3的例子。

答案 1 :(得分:5)

请参阅“CustomSort”功能here

List<string> list = new List<string>() { 
                    "0-5.jpeg",
                    "0-9.jpeg",
                    "0-0.jpeg",
                    "0-1.jpeg",
                    "0-10.jpeg",
                    "0-12.jpeg"};
list.CustomSort().ToList().ForEach(x => Console.WriteLine(x));

其输出:

0-0.jpeg
0-1.jpeg
0-5.jpeg
0-9.jpeg
0-10.jpeg
0-12.jpeg

答案 2 :(得分:4)

要解决此问题,您可以使用 StrCmpLogicalW Windows API。

有关详细信息,请参阅This Artice

答案 3 :(得分:4)

我知道这可能会迟到,但这是另一种完美运作的解决方案

FileInfo[] files = di.GetFiles().OrderBy(n => Regex.Replace(n.Name, @"\d+", n => n.Value.PadLeft(4, '0')));

OrderBy Clause

中使用Regex替换

Regex.Replace(n.Name, @"\d+", n => n.Value.PadLeft(4, '0'))

这是做什么的,它pads文件名中的数值,每个数字的长度为4个字符:

0-0.jpeg     ->   0000-0000.jpeg
0-1.jpeg     ->   0000-0001.jpeg
0-5.jpeg     ->   0000-0005.jpeg
0-9.jpeg     ->   0000-0009.jpeg
0-10.jpeg    ->   0000-0010.jpeg
0-12.jpeg    ->   0000-0012.jpeg

但这只发生在OrderBy子句中,它不会以任何方式触及原始文件名。你最终将在数组中的顺序是&#34;人类自然&#34;顺序。

答案 4 :(得分:0)

您的文件名似乎是结构化的。如果你只是对它们进行排序,它们将排序为普通字符串你需要:

  1. 将文件名解析为其组成部分。
  2. 将数字段转换为数值。
  3. 按所需顺序比较该结构以获得预期的归类序列。
  4. 就个人而言,我会创建一个表示文件名中隐含的结构的类。也许它应该包裹FileInfo。该类的构造函数应将文件名解析为其组成部分,并适当地实例化该类的属性。

    该类应实现IComparable / IComparable<T>(或者您可以创建Comparer的实现。)

    对对象进行排序,然后它们应按照您想要的整理顺序出现。

    如果您的文件名看起来像由3部分组成:

    • 高阶数值(让我们称之为'hi'),
    • 一个低阶数值(我们称之为'lo'),
    • 和一个扩展名(让我们称之为'ext')

    所以你的课可能看起来像

    public class MyFileInfoWrapper : IComparable<MyFileInfoWrapper>,IComparable
    {
      public MyFileInfoWrapper( FileInfo fi )
      {
        // your implementation here
        throw new NotImplementedException() ;
      }
    
      public int    Hi         { get ; private set ; }
      public int    Lo         { get ; private set ; }
      public string Extension  { get ; private set ; }
    
      public FileInfo FileInfo { get ; private set ; }
    
      public int CompareTo( MyFileInfoWrapper other )
      {
        int cc ;
        if      ( other   == null     ) cc = -1 ;
        else if ( this.Hi <  other.Hi ) cc = -1 ;
        else if ( this.Hi >  other.Hi ) cc = +1 ;
        else if ( this.Lo <  other.Lo ) cc = -1 ;
        else if ( this.Lo >  other.Lo ) cc = +1 ;
        else                            cc = string.Compare( this.Extension , other.Extension , StringComparison.InvariantCultureIgnoreCase ) ;
        return cc ;
      }
    
      public int CompareTo( object obj )
      {
        int cc ;
        if      ( obj == null              ) cc = -1 ;
        else if ( obj is MyFileInfoWrapper ) cc = CompareTo( (MyFileInfoWrapper) obj ) ;
        else throw new ArgumentException("'obj' is not a 'MyFileInfoWrapper' type.", "obj") ;
        return cc ;
      }
    
    }
    

答案 5 :(得分:0)

针对您的具体情况实施Comparison方法,并在Array.Sort中使用它。

private int CompareByNumericName(FileInfo firstFile, FileInfo secondFile)
{
    /* First remove '0-' and '.jpeg' from both filenames then... */

    int firstFileNumericName = Int32.Parse(firstFile.Name);
    int secondFileNumericName = Int32.Parse(secondFile.Name);

    return firstFileNumericName.CompareTo(secondFileNumericName);
}

FileInfo[] files = di.GetFiles();
Array.Sort<FileInfo>(files, CompareByNumericName);

答案 6 :(得分:0)

这是我的解决方案。我首先解析文件路径,然后定义顺序规则。

对于以下代码,您需要名称空间void Fifth_task(std::list<std::string>& lst) { std::list<std::string>::iterator it; std::set<char> seen; lst.remove_if([&](const std::string& s) { char c = std::tolower(s[0]); bool remove = (seen.count(c) > 0); seen.insert(c); return remove; }); for (it = lst.begin(); it != lst.end(); ++it) { std::cout << *it << std::endl; } }

System.Text.RegularExpressions