2011-06-23 65 views
4

我有一個面試問題問這個:映射數字字母

文本文件有以下行>

  1: A C D 
      4: A B 
      5: D F 
      7: A E 
      9: B C 

*每一行都有一個唯一的整數,後面跟一個冒號和一個或 更多字母。這些信件是 分隔空間(一個或多個)>

      #2 Write a short program in the language 
您選擇輸出排序的 列表像

  A: 1 4 7 
      B: 4 9 
      C: 1 9 
      D: 1 5 
      E: 7 
      F: 5 

我不會找人來解決它的

,但我總是對這樣的問題感到困惑。我想在C#中完成它,並想知道是否應該將每行存儲在2d數組中?處理這個問題的最好方法是什麼?在存儲之後,我如何用字母而不是數字重新排列每行?

只是在這裏尋找指針。

+5

如果你不斷地嘗試,直到找到解決這個問題,而不是要求別人的你只會增長。它很好被卡住,撞在牆上。教你許多事情,包括解決問題。 –

回答

0

我會用一個Dictionary<string,List<int>>我會讀輸入和在A,B,C等關鍵字A,C,D,A處向列表中添加1,因此結果只是通過字母查找。 所以像這樣,在非深奧的方式:

string inp = @"1: A C D 
      4: A B 
      5: D F 
      7: A E 
      9: B C"; 
      Dictionary<string, List<int>> res = new Dictionary<string, List<int>>(); 
      StringReader sr = new StringReader(inp); 
      string line; 
      while (null != (line = sr.ReadLine())) 
      { 
       if (!string.IsNullOrEmpty(line)) 
       { 
        string[] tokens = line.Split(": ".ToArray(),StringSplitOptions.RemoveEmptyEntries); 
        int idx = int.Parse(tokens[0]); 
        for (int i = 1; i < tokens.Length; ++i) 
        { 
         if (!res.ContainsKey(tokens[i])) 
          res[tokens[i]] = new List<int>(); 
         res[tokens[i]].Add(int.Parse(tokens[0])); 
        } 
       } 
      } 

資源將包含數字的信紙>列表的結果。

+0

如果文本文件以字母開頭,我可以理解這一點。但是,這些字母會多次出現,您會如何閱讀將A置爲關鍵字的輸入,因爲A可能會出現多次? – oJM86o

+0

@ oJM86o每次您在字典中找到一個密鑰時,您都會在該位置獲取該列表並將int添加到該列表中。 –

+0

我不認爲我明白,如果文本文件以數字開頭,那麼您的列表是如何開始的,即鍵是字符串。字符串/字符在每行中出現多次。你是從一本不同的字典開始,並在稍後改變它? – oJM86o

1

,這將幫助你解決這個

IDictionary<char, IList<int> > 

然而,另一個LINQ的手淫實現的東西( 「看媽媽,沒有循環!」)

using System; 
using System.IO; 
using System.Linq; 

public static class Program 
{ 
    public static void Main(string[] args) 
    { 
     File.ReadAllLines("input.txt") 
      .Select(line => 
      { 
       var split = line.Split(":".ToCharArray(), 2); 
       return new { digit = split[0].Trim().Substring(0,1), 
        chars = split[1] 
         .Split(" \t".ToCharArray()) 
         .Select(s=>s.Trim()) 
         .Where(s => !String.IsNullOrEmpty(s)) 
         .Select(s => s[0]) 
        }; 
      }) 
      .SelectMany(p => p.chars.Select(ch => new { p.digit, ch })) 
      .GroupBy(p => p.ch, p => p.digit) 
      .ToList() 
      .ForEach(g => Console.WriteLine("{0}: {1}", g.Key, string.Join(" ", g))); 
    } 
} 

當然你也可以更換GroupByToLookup

2

您可以通過創建一個Lookup將字母映射到一組數字。您可以使用擴展方法ToLookup創建Lookup


警告:劇透提前

使用LINQ,你可以做這樣的(無效輸入中斷):

var text = @"1: A C D 
4: A B 
5: D F 
7: A E 
9: B C"; 

var lookup = text 
    .Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) 
    .Select(
    line => new { 
     Number = Int32.Parse(line.Split(':').First()), 
     Letters = line.Split(':').Skip(1).First().Split(
     new[] {' '}, StringSplitOptions.RemoveEmptyEntries 
    ) 
    } 
) 
    .SelectMany(x => x.Letters, (x, letter) => new { x.Number, Letter = letter }) 
    .OrderBy(x => x.Letter) 
    .ToLookup(x => x.Letter, x => x.Number); 

foreach (var item in lookup) 
    Console.WriteLine(item.Key + ": " + String.Join(" ", item.ToArray())); 
+0

這是我見過的最好的c#代碼 - 非常地道,像紅寶石 - 謝謝! –

0

使用Split(「:」)和Split(「」)進行字符串解析。 然後填寫

Dictionary<int, List<string>> 

,並把它翻譯成

Dictionary<string, List<int>> 
0

你可以輸入存儲在一個IDictionary,並扭轉這種局面產生的輸出。

看看this question

1

如果你熟悉LINQ下面的代碼可以給你你在找什麼:

var result = File.ReadAllLines("inFile").SelectMany(line => 
       { 
        var ar = line.Split(" ".ToCharArray()); 
        var num = int.Parse(ar[0].Split(":".ToCharArray())[0]); 
        return ar.Skip(1).Select(s => new Tuple<string, int>(s, num)); 
       }).GroupBy(t => t.Item1).OrderByDescending(g => g.Count()) 
       .Select(g => g.Key + ": " + g.Select(t => t.Item2.ToString()).Aggregate((a,b) => a + " " + b)); 
      File.WriteAllLines("outFile", result); 
+1

直到C#降級到新的Perl只是一個時間問題(但受到正則表達式挑戰的用戶)。證明完畢 – sehe

+0

@sehe yes同意。似乎是編寫難懂代碼的挑戰 –

+0

我希望人們可以走出命令式編程世界並看到函數式編程世界 – Ankur

1

我知道你說你不想完全的答案,但這種事情很有趣。它看起來像其他人都拿出了類似的解決方案,但這裏的另一種方式來表示它 - (!但很多括號)的代碼「一條線」 :)

var data = @"1: A C D 
4: A B 
5: D F 
7: A E 
9: B C"; 

Console.WriteLine(
    String.Join(
     Environment.NewLine, 
     (from line in data.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) 
     let lineParts = line.Split(new[] { ':', ' ' }, StringSplitOptions.RemoveEmptyEntries) 
     from letter in lineParts.Skip(1) 
     select new { Number = lineParts[0], Letter = letter }) 
     .ToLookup(l => l.Letter, l => l.Number) 
     .OrderBy(l => l.Key) 
     .Select(l => String.Format("{0}: {1}", l.Key, String.Join(" ", l))))); 

哦,我會寫這樣的代碼在生產?可能不會,但在這樣的運動中很有趣!

0

我看到多個相似的(循環)和不相似的(linq)解決方案已經發布,但是因爲我寫了這個,我想我會把它放在混合中。

static void Main(string[] args) 
{ 
    var result = new SortedDictionary<char, List<int>>(); 
    var lines = System.IO.File.ReadAllLines(@"input.txt"); 
    foreach (var line in lines) 
    { 
     var split = line.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries); 
     var lineNumber = Int32.Parse(split[0].Substring(0,1)); 
     foreach (var letter in split.Skip(1)) 
     { 
      var key = letter[0]; 
      if (!result.ContainsKey(key)) 
      { 
       result.Add(key, new List<int> { lineNumber }); 
      } 
      else 
      { 
       result[key].Add(lineNumber); 
      } 
     } 
    } 
    foreach (var item in result) 
    { 
     Console.WriteLine(String.Format("{0}: {1}", item.Key, String.Join(" ", item.Value))); 
    } 
    Console.ReadKey(); 
} 
0

面試過程的一個重要部分是詢問和驗證假設。雖然您的描述聲明文件的結構爲整數後跟字母,但您給出的示例按遞增順序顯示整數。如果是這樣的話,你能避免所有的LINQ瘋狂和實施更有效的解決方案:

var results = new Dictionary<char, List<int>>(); 

foreach (var line in File.ReadAllLines(@"input.txt")) 
{ 
    var split = line.Split(new []{' '}, StringSplitOptions.RemoveEmptyEntries); 
    var num = int.Parse(split[0].TrimEnd(':')); 

    for (int i = 1; i < split.Length; i++) 
    { 
     char letter = split[i][0]; 
     if (!results.ContainsKey(letter)) 
      results[letter] = new List<int>(); 

     results[letter].Add(num); 
    } 
}