2016-06-08 5 views
0

고유 한 열 SPAME이있는 데이터베이스에 "GEM"테이블이 있습니다. 각 레코드 값은 하나 개의 문자와 숫자 예 구성문자열의 이전 번호 찾기

F12, T16, K15, F10, K14, T9, T7

I 단지 선택된 하나 전에 번호를 확인하고자

입력 : F12 출력 : F10

입력 : T9 출력 : T7

,369,136 예

입력 : T16 출력 : 나쁜 성능 될 것 같은 T9

내가 DB 입력 한 전에 각 번호를 검색 할 다음 숫자 상관 없음을 제거하지 생각했지만 소리.

Gem gem; 
    for(i= input; i>0; i--) 
    { 
     gem = Uow.Gems.GetAll().FirstOrDefault(x=> RemoveChar(x.SpName) == input) 
     If(gem!=null) break; 
    } 

팁이 있습니까? 당신이 원하는 것을 할 (등등은 ... 예외 처리없이)

+2

가장 좋은 것은, 가능하다면, 귀하의 DB를 변경하는 것 문자와 숫자를 별도의 열로 구분하십시오. – juharr

+0

Thx juharr,하지만 그렇게 할 수는 없습니다. – Maro

+0

나쁜 성능이라고하기 전에 테스트 해 보셨습니까? 그렇지 않다면, 당신이하는 것이 좋습니다. –

답변

1

못생긴 방법 :

중요 사항 :이 작업을 수행하는 가장 좋은 방법은 열 등을 추가하여 DB를 변경하는 것을 잊지 마세요 juharr가 말했습니다.

List<string> ints = new List<string>(); 
    ints.Add("F12"); 
    ints.Add("T16"); 
    ints.Add("K15"); 
    ints.Add("F10"); 
    ints.Add("K14"); 
    ints.Add("T9"); 
    ints.Add("T7"); 

    var ordered = ints.Select((s, i) => new 
    { 
     nb = int.Parse(s.Substring(1)), 
     text = s.Substring(0, 1), 
     val = s, 
    }).OrderBy(arg => arg.text).ThenBy(arg => arg.nb).ToList(); 

    var index = ordered.FindIndex(arg => arg.val == "T16"); 
    Console.WriteLine(ordered[index - 1].val); 
    Console.ReadLine(); 
+0

확장 클래스로'FindIndex'를 왜 추가해야합니까? LINQ는 그 방법을 제공합니다. – Andy

1

나는이 값이 당신이 후 반환 할 것이라고 생각합니다;

public string GetPrevious(string value) 
    { 
     var list = new[] 
     { 
      new {SPName = "F12"}, 
      new {SPName = "T16"}, 
      new {SPName = "K15"}, 
      new {SPName = "F10"}, 
      new {SPName = "K14"}, 
      new {SPName = "T9"}, 
      new {SPName = "T7"} 
     }; 

     return 
      list.Where(
       l => l.SPName.ToCharArray().First() == value.ToCharArray().First() && 
        GetValue(l.SPName) < GetValue(value)).OrderByDescending(l => GetValue(l.SPName)).First().SPName; 
    } 

    public int GetValue(string value) 
    { 
     return int.Parse(value.Substring(1, value.Length - 1)); 
    } 

불행하게도 그이 (내가 제안하고 있지 않다 당신이 그것을 게시) 원래의 테이블 데이터를 필요없이 많은 값으로 실행됩니다 얼마나 빨리 알고 어렵다.

+0

테이블에 1,431,600 개의 레코드가 있습니다. – Maro

+0

나는 그런 식으로 생각했습니다. 문자열 길이로 필터링 해 보았습니까? 결과가 입력보다 길지 않을 것입니다. 느린 작업을 수행하기 전에 기본적으로 세트의 크기를 줄이는 효율적인 방법이 필요합니다. –

1

방법이,하지만 성능이 확실하지에 대한 당신에게 인덱스 SQL에서 SPName LIKE 'T%@' 그렇게 사용해야한다 제공한다 :

var input = "T9"; 
var Gem = Uow.Gems.Where 
     (g => g.SPName.StartsWith(input.Substring(0,1)) && 
       Convert.ToInt32(g.SPName.Substring(1)) < 
        Convert.ToInt32(input.Substring(1))) 
    .OrderByDescending(g => Convert.ToInt32(g.SPName.Substring(1))) 
    .Take(1); 

I는이 SQL 생성해야 이해 할수 :

-- Region Parameters 
DECLARE @p0 VarChar(1000) = 'F%' 
DECLARE @p1 Int = 1 
DECLARE @p2 Int = 12 
DECLARE @p3 Int = 1 
-- EndRegion 
SELECT TOP (1) [t0].[SPName] 
FROM [Gem] AS [t0] 
WHERE ([t0].[SPName] LIKE @p0) AND ((CONVERT(Int,SUBSTRING([t0].[SPName], @p1 + 1, CONVERT(Int,DATALENGTH([t0].[SPName]))))) < @p2) 
ORDER BY CONVERT(Int,SUBSTRING([t0].[SPName], @p3 + 1, CONVERT(Int,DATALENGTH([t0].[SPName])))) DESC 
1

을 나는 모든 보석을 채우는 간단한 캐시와 비교자를 사용하는 순서를 사용하는 접근법을 제안 할 것이다. 발견되지 않는 경우는

 // Use your Uow.Gems.GetAll() list of gems 
     string[] gems = new string[] { "F12", "T16", "K15", "F10", "K14", "T9", "T7", "A12", "A11" }; 

     string input = "A12"; 

     //Cache it something like this Uow.Gems.GetAll().OrderBy(x => x, new GemComparer()).ToList() 
     var cacheGems = gems.OrderBy(x => x, new GemComparer()); 

     foreach (var thing in cacheGems) 
     { 
      Console.WriteLine(thing); 
     } 

     var previous = cacheGems.TakeWhile(x => x != input).LastOrDefault(); 

     var next = cacheGems.SkipWhile(x => x != input).Skip(1).FirstOrDefault(); 

     Console.WriteLine(previous); 

     Console.WriteLine(next); 

는 비어 있습니다

A11 A12 F10 F12 K14 K15 T16 T7 T9'

출력 : 이전 : A11, 다음의 F10

public class GemComparer : IComparer<string> 
    { 
     public int Compare(string s1, string s2) 
     { 
      if (IsNumeric(s1) && IsNumeric(s2)) 
      { 
       if (Convert.ToInt32(s1) > Convert.ToInt32(s2)) return 1; 
       if (Convert.ToInt32(s1) < Convert.ToInt32(s2)) return -1; 
       if (Convert.ToInt32(s1) == Convert.ToInt32(s2)) return 0; 
      } 

      if (IsNumeric(s1) && !IsNumeric(s2)) 
       return -1; 

      if (!IsNumeric(s1) && IsNumeric(s2)) 
       return 1; 

      return string.Compare(s1, s2, true); 
     } 

     public static bool IsNumeric(object value) 
     { 
      try 
      { 
       int i; 
       return int.TryParse(value.ToString(), out i); 
      } 
      catch (FormatException) 
      { 
       return false; 
      } 
     } 
    }