2009-03-24 20 views
5

Đây là một vấn đề đơn giản. Tôi có một ứng dụng có số điện thoại như "13335557777" và cần phải đảo ngược và chèn dấu chấm giữa mỗi số, như sau:C# string manipulation problem

"7.7.7.7.5.5.5.3.3.3.1."

Tôi biết tôi có thể làm điều này với một StringBuilder và một for-loop để đảo ngược chuỗi và chèn các dấu chấm, nhưng là có một cách thông minh để làm điều này trong LINQ (hoặc một số cách khác)?

Lưu ý: vì điều này, tôi không thực sự quan tâm đến hiệu suất hoặc cấp phát bộ nhớ hay bất cứ điều gì, chỉ tò mò để xem làm thế nào điều này sẽ được thực hiện trong LINQ.

+0

Bạn có thực sự muốn một dấu chấm sau 1 cuối cùng không? Nếu vậy, nó hơi thay đổi vấn đề. –

+0

Vâng, điều đó không rõ ràng. Nó không thực sự quan trọng, tôi sẽ đưa ra các giải pháp làm theo cách này. –

Trả lời

8

Hãy thử điều này

var source = GetTheString(); 
var reversed = source.Reverse().Select(x => x.ToString()).Aggregate((x,y) => x + "." + y); 

EDIT

Giải pháp này chắc chắn là nhằm vào "thông minh" kết thúc. Nó có khả năng thực hiện nhiều hơn để sử dụng một StringBuilder để xây dựng chuỗi. Giải pháp này tạo ra nhiều chuỗi trung gian.

EDIT2

Có một số cuộc tranh luận về tốc độ tương đối của các giải pháp "thông minh" so với các phương pháp StringBuilder. Tôi đã viết một chuẩn mực nhanh để đo lường cách tiếp cận. Theo dự kiến, StringBuilder nhanh hơn.

  • Bình thường tổng hợp (100 phần tử): 00: 00: 00,0418640
  • WithStringBuilder (100 phần tử): 00: 00: 00,0040099
  • Bình thường tổng hợp (1000 phần tử): 00: 00: 00,3062040
  • WithStringBuilder (1000 phần tử): 00: 00: 00,0405955
  • Bình thường tổng hợp (10000 phần tử): 00: 00: 03,0270392
  • WithStringBuilder (10000 phần tử): 00: 00: 00,4149977

Tuy nhiên, có hay không chênh lệch tốc độ là dấu hiệu phụ thuộc nhiều vào nơi nó thực sự được sử dụng trong ứng dụng của bạn.

Mã cho điểm chuẩn.

public static class AggregateUnchanged { 
    public static string Run(string input) { 
     return input 
      .Reverse() 
      .Select(x => x.ToString()) 
      .Aggregate((x, y) => x + "." + y); 
    } 
} 

public static class WithStringBuilder { 
    public static string Run(string input) { 
     var builder = new StringBuilder(); 
     foreach (var cur in input.Reverse()) { 
      builder.Append(cur); 
      builder.Append('.'); 
     } 

     if (builder.Length > 0) { 
      builder.Length = builder.Length - 1; 
     } 

     return builder.ToString(); 
    } 
} 

class Program { 
    public static void RunAndPrint(string name, List<string> inputs, Func<string, string> worker) { 

     // Test case. JIT the code and verify it actually works 
     var test = worker("123456"); 
     if (test != "6.5.4.3.2.1") { 
      throw new InvalidOperationException("Bad algorithm"); 
     } 

     var watch = new Stopwatch(); 
     watch.Start(); 
     foreach (var cur in inputs) { 
      var result = worker(cur); 
     } 
     watch.Stop(); 
     Console.WriteLine("{0} ({2} elements): {1}", name, watch.Elapsed, inputs.Count); 
    } 

    public static string NextInput(Random r) { 
     var len = r.Next(1, 1000); 
     var builder = new StringBuilder(); 
     for (int i = 0; i < len; i++) { 
      builder.Append(r.Next(0, 9)); 
     } 
     return builder.ToString(); 
    } 

    public static void RunAll(List<string> input) { 
     RunAndPrint("Normal Aggregate", input, AggregateUnchanged.Run); 
     RunAndPrint("WithStringBuilder", input, WithStringBuilder.Run); 
    } 

    static void Main(string[] args) { 
     var random = new Random((int)DateTime.Now.Ticks); 
     RunAll(Enumerable.Range(0, 100).Select(_ => NextInput(random)).ToList()); 
     RunAll(Enumerable.Range(0, 1000).Select(_ => NextInput(random)).ToList()); 
     RunAll(Enumerable.Range(0, 10000).Select(_ => NextInput(random)).ToList()); 
    } 
} 
+0

Để biết thông tin, trong khi "thông minh" và "FP", tôi không chắc đó là lời khuyên tốt ... số lượng các chuỗi trung gian có nghĩa là 'StringBuilder' sẽ thực dụng hơn. –

+0

@Marc, đồng ý, họ yêu cầu thông minh mặc dù vậy tôi cảm thấy bị bắt buộc :) – JaredPar

+0

Vâng, không sao cả, tôi đã yêu cầu thông minh bằng mọi chi phí khác. –

0

(loại bỏ một câu trả lời bằng cách sử dụng danh sách char)

Theo bình luận trên bài khác, quan điểm của tôi là trong khi các LINQ vv có thể là "thông minh", nó không nhất thiết phải là hiệu quả. Nó sẽ làm cho rất nhiều chuỗi trung gian cần được thu thập, ví dụ.

Tôi muốn gắn liền với StringBuilder v.v. trừ khi bạn có lý do chính đáng để thay đổi nó.

+0

Tại sao lại sử dụng StringBuilder khi có String.Join cho mục đích cụ thể này? –

+0

@Grauenwolf - bởi vì string.Join hoạt động trên một chuỗi [], không phải là char [], vì vậy trước tiên bạn cần tạo một chuỗi các chuỗi. Với StringBuilder bạn không cần phải làm điều đó. –

1
 string x = "123456"; 
     StringBuilder y = new StringBuilder(x.Length * 2); 

     for (int i = x.Length - 1; i >= 0; i--) 
     { 
      y.Append(x[i]); 
      y.Append("."); 
     } 
+0

"Tôi biết tôi có thể làm điều này với một StringBuilder và một for-loop để đảo ngược chuỗi và chèn các dấu chấm, nhưng là có một cách thông minh để làm điều này trong LINQ (hoặc một số cách khác)?" –

+0

Tôi chỉ đưa cho anh ấy mã để anh ấy không phải viết nó, giật – Nick

+0

Tôi ở cùng anh, Nick. +1 –

-1

Miễn là bạn đang trải qua một mảng, sẽ dễ sử dụng chuỗi hơn.Tham gia:

string[] source = GetTheStringAsArray(); 
string reversed = string.Join(".", source.Reverse()); 
+0

Bạn đã bỏ qua bước đầu tiên, chia chuỗi thành một mảng hoặc danh sách. –

+0

nội dung chuỗi = "35557777"; là một mảng :) –

+0

Hãy cho tôi biết bạn đã không bỏ phiếu cho câu trả lời của tôi và sau đó gửi của riêng bạn bằng cách sử dụng về cơ bản các chức năng tương tự ... –

0
string aString = "13335557777"; 
string reversed = (from c in aString.Reverse() 
       select c + ".").Aggregate((a, b) => a + b); 
0

Đây có phải là thực sự là một vấn đề LINQ? Chỉ hoạt động ngược trong một vòng lặp cho mỗi ký tự:

string s = ""; 
string content = "35557777"; 
for (int i = content.Length -1; i > 0; i--) 
{ 
    s += content[i] + "."; 
} 
Console.WriteLine(s); 
Console.ReadLine(); 

Nếu đó là chuỗi dài hơn 4k, hãy sử dụng StringBuilder. Sử dụng LINQ cho "7.7.7.7.5.5.5.3.3.3.1." không phải là những gì LINQ là cho, đánh dấu tôi đến -99 nếu bạn muốn, và Marc quá.

+0

Cảm ơn câu trả lời. Tôi biết làm các thao tác chuỗi như thế này không thực sự là một vấn đề LINQ, nhưng đây là một câu hỏi kiểu "thuật toán". Có lẽ nó sẽ tốt hơn nếu tôi sử dụng một danh sách các đối tượng thay vì một chuỗi. –

2

Lợi ích của việc này là String.Join sẽ rẻ hơn ".Gregregate ((x, y) => x +". "+ Y)".

var target = string.Join(".", source.Reverse().Select(c => c.ToString()).ToArray()); 
+0

Đẹp, có lẽ là câu trả lời hay nhất ở đây, imho ... – Tracker1