2017-01-13 105 views
0

각 부분 문자열이 들어있는 문자열 목록이 있습니다. 그 부분 문자열의 숫자 값을 기준으로 순서를 바꾸고 싶습니다.C#을 사용하여 숫자 부분 문자열에 문자열 목록을 정렬하는 방법

List<string> strings= new List<string> 
{ 
    "some-name-(1).jpg", 
    "some-name-(5).jpg", 
    "some-name-(5.1).jpg", 
    "some-name-(6).jpg", 
    "some-name-(12).jpg" 
}; 

수는 항상 String.IndexOf가 신뢰할 사용하여 문자열의 유일한 괄호입니다 괄호로 둘러싸여됩니다 세트는 훨씬 더 큰이 같은, 그러나 보일 것입니다. 누락 된 숫자가있을뿐만 아니라 정수가 아닌 소수도있을 수 있습니다.

나는 그 부분 문자열의 수치 값으로 정렬 된 동일한 문자열의 재정렬 된 목록을 얻는 데 정말로 힘든 시간을 보내고 있습니다. 누구든지이 일을 잘 수행 할 수있는 방법이 있습니까? 감사.

+0

[이] (http://stackoverflow.com/a/7215364/4802649) 도움이 될 수있다. – Phiter

+0

또는 다른 솔루션은 https://www.bing.com/search?q=c%23+natural+sort에서 찾을 수 있습니다. 표준 중복 타겟 http://stackoverflow.com/questions/248603/natural-sort-order -in-c-sharp는 시작하기에 충분한 정보를 제공합니다.이 질문에 대한 답은 좀 더 자세한 정보가 있습니다 - http://stackoverflow.com/a/3717036/477420 –

답변

2

괄호 사이의 항목이 double으로 변환 가능한지 확인합니다. 그렇지 않으면 -1을 반환합니다.

var numbers = strings.Select(x => x.Substring(x.IndexOf("(") + 1, 
    x.IndexOf(")") - x.IndexOf("(") - 1)).Select(x => 
{ 
    double val; 
    if(double.TryParse(x, out val)) { 
     return val; 
    } 

    // Or whatever you want to do 
    return -1; 
}).OrderBy(x => x); // Or use OrderByDescending 

당신은 항상 짧은 그대로 다음이를 사용, 괄호 사이의 숫자가있을 것입니다 확실한 경우 :

내가 원래 문자열이 필요

var numbers = strings.Select( 
    x => x.Substring(x.IndexOf("(") + 1, x.IndexOf(")") - x.IndexOf("(") - 1)) 
    .Select(x => double.Parse(x)) 
.OrderBy(x => x); // Or use OrderByDescending 

편집 , 그냥 그 숫자를 주문했다.

var items = strings.OrderBy(
    x => double.Parse(x.Substring(x.IndexOf("(") + 1, 
    x.IndexOf(")") - x.IndexOf("(") - 1))); 

어떻게 OO 접근 방식에 대해 :

은 기본적으로 당신이 할 필요는 OrderBy에 술어를 통과하여 그 번호로 주문을 얘기하는 것입니다?

우리는 문자열을 주문하지만 숫자처럼 취급해야합니다. 우리가 방금 OrderBy라고 부를 수있는 방법이 있다면 그것은 좋지 않을까요? 그것은 우리를 위해 주문합니까? 잘있다. OrderBy 메서드는 IComparable<T> (있는 경우)을 사용합니다. jpg 경로를 보유하고 IComparable<T> 인터페이스를 구현하는 클래스를 생성 해 봅시다. 위의 방법에 대한 좋은 무엇

public class CustomJpg : IComparable<CustomJpg> 
{ 
    public CustomJpg(string path) 
    { 
     this.Path = path; 
    } 

    public string Path { get; private set; } 

    private double number = -1; 

    // You can even make this public if you want. 
    private double Number 
    { 
     get 
     { 
      // Let's cache the number for subsequent calls 
      if (this.number == -1) 
      { 
       int myStart = this.Path.IndexOf("(") + 1; 
       int myEnd = this.Path.IndexOf(")"); 
       string myNumber = this.Path.Substring(myStart, myEnd - myStart); 
       double myVal; 
       if (double.TryParse(myNumber, out myVal)) 
       { 
        this.number = myVal; 
       } 
       else 
       { 
        throw new ArgumentException(string.Format("{0} has no parenthesis or a number between parenthesis.", this.Path)); 
       } 
      } 

      return this.number; 
     } 
    } 

    public int CompareTo(CustomJpg other) 
    { 
     if (other == null) 
     { 
      return 1; 
     } 

     return this.Number.CompareTo(other.Number); 
    } 
} 

우리가 OrderBy를 계속 전화하는 경우, 그것은 개방 () 종료와 수의 해석마다하고 검색 할 필요가 없습니다 것입니다. 처음 호출 될 때 캐시에 저장 한 다음 계속 사용합니다. 다른 좋은 점은 Path 속성과 Number 속성을 바인딩 할 수 있다는 것입니다 (액세스 수정자를 private에서 변경해야 함). 축소판 이미지를 보유하고 바인딩 할 수있는 새 속성을 도입 할 수도 있습니다. 보시다시피이 접근법은 훨씬 더 유연하고 깨끗하며 OO 방식입니다. 숫자를 찾기위한 코드도 한 곳에 있으므로 ()에서 다른 기호로 전환하면 한 곳에서 변경됩니다. 또는 ()을 찾기 위해 수정할 수 있으며 찾지 못하면 다른 기호를 찾습니다.

List<CustomJpg> jpgs = new List<CustomJpg> 
{ 
    new CustomJpg("some-name-(1).jpg"), 
    new CustomJpg("some-name-(5).jpg"), 
    new CustomJpg("some-name-(5.1).jpg"), 
    new CustomJpg("some-name-(6).jpg"), 
    new CustomJpg("some-name-(12).jpg") 
}; 

var ordered = jpgs.OrderBy(x => x).ToList(); 

당신은 어떤 개체에 대해이 방법을 사용할 수 있습니다 여기에

은 사용입니다.

+0

거룩한 암소. 인라인 익명 함수입니까? 나는 전에 그것을 본 적이 없다. 시원한! 이것은 효과가있는 것처럼 보입니다. –

+0

@JacobStamm 미안하지만 내 대답을 편집했습니다. 번호를 얻는 데 약간의 문제가 있었지만 지금은 효과가 있습니다. – CodingYoshi

+0

이것의 문제점은 실제 숫자를 반환한다는 것입니다. 그러나 그 숫자에 대해서만 주문 된 원래 문자열이 필요합니다. 이제는 그 숫자를 사용하여 원래 문자열 목록에서 부분 문자열 조회를 할 수 있지만 몇 가지 문제가 있습니다. 첫째, 항목마다 한 번 전체 문자열 목록을 반복해야합니다. 둘째, 중복 번호가 있으면 좋지 않습니다. 이것이 내가 피하려고했던 것입니다. –

1

닫는 괄호 ")"에서 시작하는 부분을 처음으로 자른 경우에는 부분 문자열을 더 쉽게 선택할 수 있습니다. 즉, "some-name-(5.1).jpg"에서 먼저 "some-name-(5.1"을 얻습니다. 그런 다음 "(" 뒤 부분을 맡으십시오. 두 번째 Substring은 자동으로 문자열의 끝까지 모든 정보를 가져 오므로 길이 계산이 저장됩니다.

strings = strings 
    .OrderBy(x => Decimal.Parse(
         x.Substring(0, x.IndexOf(")")) 
         .Substring(x.IndexOf("(") + 1) 
       ) 
    ) 
    .ToList(); 

이 여기에 매우 중요 아마 아니지만, 일반적으로 decimal 저장 번호는 더 정확하게 double보다 10 진법으로 주어진다. double17.217.19999999999999으로 변환 할 수 있습니다.

+0

두 가지 유용한 정보에 감사드립니다. 나는 실제로 당신과 @ CodingYoshi의 답을 결합하여 가장 똑 바르고 앞으로 나아갈 수있는 것을 얻었습니다. 그리고 네, 제 목적을 위해, 정확성, 단지 서수 값을 신경 쓰지 않기 때문에'double'은 잘 작동 할 것입니다. –

1

위의 예제 코드는 숫자로 정렬 된 숫자 목록을 반환하지만 "some-name- (001)"과 같은 숫자의 시작 부분에 이름이 같은 파일 이름 목록을 더 잘 나타내려면 " .JPG "당신은 단순히 위해

List<string> strings = new List<string> 
     { 
      "some-name-(001).jpg", 
      "some-name-(005.1).jpg", 
      "some-name-(005).jpg", 
      "some-name-(004).jpg", 
      "some-name-(006).jpg", 
      "some-name-(012).jpg" 
     }; 
     var orederedByName =strings.Select(s =>s).OrderBy(s=>s); 
+0

좋은 팁이지만 이름이 항상 "some-name"이되는 것은 아닙니다. 이름은 다양합니다. 그래서 그 경우에는 괄호 사이에있는 숫자가 무엇이든간에 주문해야합니다. –

+1

@JacobStamm 이름이 다를지라도 괄호 사이에 0으로 채워진 문자열을 추출 할 수 있으며 숫자 구문 분석을 처리하지 않고도 정렬 할 수 있습니다. – Abion47