2017-12-24 14 views
0

각 줄마다 하나씩 텍스트 파일이 있습니다. 이 문자열 중 일부는 알 수없는 "@"문자를 포함합니다. 각 "@"는 숫자 1, 2, 3 또는 4를 나타낼 수 있습니다. "@"각각에 대해 문자열의 모든 가능한 조합 (순열?)을 생성하려고합니다. 문자열 당 설정된 수의 "@"이 있으면 루프 (중첩 및 더티) 용으로 중첩 된 것을 사용합니다. 알 수없는 "@"숫자를 사용하여보다 우아한 방법을 찾는 데 도움이 필요합니다.알 수없는 슬롯 수를 가진 모든 조합을 생성하십시오.

예 1 : 입력 문자열 [email protected]

출력 스트링이 될 것이다 :

a1bc 
a2bc 
a3bc 
a4bc 

예 2

a1bc1d 
a1bc2d 
a1bc3d 
a1bc4d 
a2bc1d 
a2bc2d 
a2bc3d 
... 
a4bc3d 
a4bc4d 

: 입력 문자열 [email protected]@d

출력 스트링이 될 것이다 누구든지 이걸로 도울 수 있니? 나는 C#을 사용하고있다.

답변

0

사실이 함수는 실제로 재귀 함수로 사용하기에 좋습니다. 나는 C#을 쓰지 않지만 문자열을 받아들이고 확장 된 문자열을 포함하는 배열을 반환하는 함수 List<String> expand(String str)을 만들 것이다.

expand 다음 문자열을 검색하여 첫 번째 @을 찾고 문자열 + 확장의 첫 번째 부분을 포함하는 목록을 만들 수 있습니다. 그런 다음 문자열의 마지막 부분에서 expand을 호출하고 마지막 부분의 확장에서 각 요소에 확장의 각 요소를 추가 할 수 있습니다. 자바 ArrayLists를 사용

예 구현 :

ArrayList<String> expand(String str) { 

    /* Find the first "@" */ 
    int i = str.indexOf("@"); 

    ArrayList<String> expansion = new ArrayList<String>(4); 
    /* If the string doesn't have any "@" */ 
    if(i < 0) { 
     expansion.add(str); 
     return expansion; 
    } 

    /* New list to hold the result */ 
    ArrayList<String> result = new ArrayList<String>(); 

    /* Expand the "@" */ 
    for(int j = 1; j <= 4; j++) 
     expansion.add(str.substring(0,i-1) + j); 

    /* Combine every expansion with every suffix expansion */ 
    for(String a : expand(str.substring(i+1))) 
     for(String b : expansion) 
      result.add(b + a); 
    return result; 
} 
0

나는 콘솔 응용 프로그램에서 아래의 코드를 테스트했다. 요구 사항을 충족하는지 확인하십시오. 여기서 주요 아이디어는 주어진 문자열을 부분들로 분할하고 가능한 모든 출력을 구성하는 것입니다. 여기

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      //string value = "[email protected]"; 
      string value = "[email protected]@d"; 
      //string value = "[email protected]@[email protected]"; 

      var array = Generate(value); 
      foreach (string str in array) 
      { 
       Console.WriteLine(str); 
      } 

      Console.ReadKey(); 
     } 

     // This method will initiate generation of 
     // all combinations for given value 
     static string[] Generate(string value) 
     { 
      string[] parts = value.Split(new string[] { "@" }, StringSplitOptions.None); 

      var count = (int)Math.Pow(4, parts.Length - 1); 

      string[] array = new string[count]; 

      int index = 0; 
      Generate(array, ref index, parts[0], 1, parts); 

      return array; 
     } 

     // Here we generate all possible combinations 
     // with recursion 
     static void Generate(string[] array, ref int index, string value, int level, string[] parts) 
     { 
      bool flag = level + 1 < parts.Length; 

      for (int i = 1; i < 5; i++) 
      { 
       string str = (value + i + parts[level]); 

       if (flag) 
       { 
        Generate(array, ref index, str, level + 1, parts); 
       } 
       else 
       { 
        array[index] = str; 
        index++; 
       } 

      } 
     } 

    } 
} 

는 스크린 샷

enter image description here

0

이 재귀 솔루션을 큰 소리로 외치고있다.

먼저 주어진 값 집합에서 특정 길이의 모든 조합을 생성하는 메소드를 만듭니다. 문자열 생성에만 관심이 있기 때문에 string이 불변이라는 사실을 활용할 수 있습니다 (P.D.2 참조). 재귀 함수를 구현하고 추론하는 것이 훨씬 쉬워집니다.

static IEnumerable<string> GetAllCombinations<T>(
    ISet<T> set, int length) 
{ 
    IEnumerable<string> getCombinations(string current) 
    { 
     if (current.Length == length) 
     { 
      yield return current; 
     } 
     else 
     { 
      foreach (var s in set) 
      { 
       foreach (var c in getCombinations(current + s)) 
       { 
        yield return c; 
       } 
      } 
     } 
    } 

    return getCombinations(string.Empty); 
} 

이 방법이 어떻게 작동하는지주의 깊게 연구하십시오. 그것을 이해하기 위해 작은 예제를 위해 손으로 직접 작업하십시오.

지금, 한 번 우리는 가능한 모든 조합을 생성하는 방법을 알고, 문자열을 구축하는 것은 쉽다 : 지정된 문자열에 와일드 카드의 수 밖으로

  1. 그림이 우리의 결합 길이 될 것입니다.
  2. 모든 조합에 대해 각 문자를 와일드 카드가있는 문자열에 순서대로 삽입하십시오.

    public static IEnumerable<string> GenerateCombinations<T>(
        this string s, 
        IEnumerable<T> set, 
        char wildcard) 
    { 
        var length = s.Count(c => c == wildcard); 
        var combinations = GetAllCombinations(set, length); 
        var builder = new StringBuilder(); 
    
        foreach (var combination in combinations) 
        { 
         var index = 0; 
    
         foreach (var c in s) 
         { 
          if (c == wildcard) 
          { 
           builder.Append(combination[index]); 
           index += 1; 
          } 
          else 
          { 
           builder.Append(c); 
          } 
         } 
    
         yield return builder.ToString(); 
         builder.Clear(); 
        } 
    } 
    

    그리고 우리는 완료 :

좋아, 그냥 작업을 수행 할 수 있습니다. 사용법은 다음과 같습니다

var set = new HashSet<int>(new[] { 1, 2, 3, 4 }); 
Console.WriteLine(
    string.Join("; ", "[email protected]@d".GenerateCombinations(set, '@'))); 

그리고 확실히 충분히, 출력은 다음과 같습니다

a1bc1d; a1bc2d; a1bc3d; a1bc4d; a2bc1d; a2bc2d; a2bc3d; 
a2bc4d; a3bc1d; a3bc2d; a3bc3d; a3bc4d; a4bc1d; a4bc2d; 
a4bc3d; a4bc4d 

이 가장 성능이 좋은 또는 효율적인 구현인가? 아마 읽을 수없고 유지할 수있는 것은 아닙니다. 회의가 아닌 특정 성과 목표를 가지고 있지 않다면 효과가 있고 이해하기 쉬운 코드를 작성하십시오.

경찰서. 모든 오류 처리 및 인수 유효성 검사를 생략했습니다.

P.D.2 : 조합의 길이가 큰 경우 GetAllCombinations 내부의 연결 문자열은 좋지 않을 수 있습니다. 이 경우 GetAllCombinationsIEnumerable<IEnumerable<T>>으로 보내고 ImmutableStack<T>을 구현하고 string 대신 조합 버퍼로 사용하십시오.

0

여기 제가 제공하는 문제에 대한 최소한의 방법을 제안합니다. 예, 다른 사람들과 마찬가지로 재귀가 여기로가는 길입니다.

재귀는 입력의 짧은 부분에 대한 솔루션을 제공하여이 문제를 해결할 수 있고 결과가 병합 될 때까지 다른 부분으로 다시 시작할 수 있으므로 완벽하게 적합합니다.

모든 재귀에는 중지 조건이 있어야합니다. 즉, 더 이상의 재귀가 필요하지 않습니다.

여기 내 정지 조건은 문자열에 더 이상 "@"이 없다는 것입니다. IEnumerable<char>이므로 문자열을 값 집합 (1234)으로 사용하고 있습니다.

다른 모든 해결책은 훌륭합니다. 짧은 접근 방식을 보여주고 싶었습니다. LINQ와

internal static IEnumerable<string> GetStrings(string input) 
{ 
    var values = "1234"; 
    var permutations = new List<string>(); 

    var index = input.IndexOf('@'); 
    if (index == -1) return new []{ input }; 

    for (int i = 0; i < values.Length; i++) 
    { 
     var newInput = input.Substring(0, index) + values[i] + input.Substring(index + 1); 
     permutations.AddRange(GetStrings(newInput)); 
    } 

    return permutations; 
} 

이보다 짧고 깨끗한 방법 :

internal static IEnumerable<string> GetStrings(string input) 
{ 
    var values = "1234"; 

    var index = input.IndexOf('@'); 
    if (index == -1) return new []{ input }; 

    return 
     values 
     .Select(ReplaceFirstWildCardWithValue) 
     .SelectMany(GetStrings); 

    string ReplaceFirstWildCardWithValue(char value) => input.Substring(0, index) + value + input.Substring(index + 1); 
}