2011-09-06 39 views
6

Tôi cần tìm chuỗi trong chuỗi lớn khác, ví dụ: {1,3,2,3} có trong {1,3,2,3,4,3}{5,1,3,2,3}. Có cách nào để thực hiện nhanh chóng với IEnumerable hoặc bằng cách nào khác không?Tìm một chuỗi trong chuỗi dài hơn

+1

là chuỗi trong một int mảng, hoặc chỉ là một chuỗi phân tách bằng dấu phẩy? –

+0

Trong thực tế, nó là một danh sách có thể được chuyển đổi thành mảng. – user906763

+0

Bạn có muốn kiểm tra xem chuỗi có nằm trong chuỗi không và trả về true/false? – BoltClock

Trả lời

1

Bạn có thể thử một cái gì đó như thế này để giúp bạn bắt đầu. Một khi bạn đã chuyển đổi danh sách này thành một chuỗi, bạn có thể tìm thấy những chuỗi bằng cách sử dụng chuỗi con:

if (String.Join(",", numericList.ConvertAll<string>(x => x.ToString()).ToArray()) 
{ 
    //get sequence 
} 
5

Phương pháp này sẽ tìm thấy một dãy con trong một chuỗi phụ huynh, của bất kỳ loại có thể được so sánh qua Equals():

public static bool ContainsSubequence<T>(this IEnumerable<T> parent, IEnumerable<T> target) 
{ 
    bool foundOneMatch = false; 
    using (IEnumerator<T> parentEnum = parent.GetEnumerator()) 
    { 
     using (IEnumerator<T> targetEnum = target.GetEnumerator()) 
     { 
      // Get the first target instance; empty sequences are trivially contained 
      if (!targetEnum.MoveNext()) 
       return true; 

      while (parentEnum.MoveNext()) 
      { 
       if (targetEnum.Current.Equals(parentEnum.Current)) 
       { 
        // Match, so move the target enum forward 
        foundOneMatch = true; 
        if (!targetEnum.MoveNext()) 
        { 
         // We went through the entire target, so we have a match 
         return true; 
        } 
       } 
       else if (foundOneMatch) 
       { 
        return false; 
       } 
      } 

      return false; 
     } 
    } 
} 

Bạn có thể sử dụng nó như thế này:

bool match = new[] {1, 2, 3}.ContainsSubsequence(new[] {1, 2}); // match == true 
match = new[] {1, 2, 3}.ContainsSubsequence(new[] {1, 3}); // match == false 

Lưu ý rằng nó giả định trình tự mục tiêu không có người null yếu tố.

Cập nhật: Cảm ơn upvotes, tất cả mọi người, nhưng có thực sự là một lỗi trong đoạn code trên! Nếu tìm thấy một phần khớp, nhưng sau đó không biến thành một kết hợp đầy đủ, quá trình này là đã kết thúc, thay vì đặt lại (rõ ràng là không được khắc phục khi áp dụng cho một cái gì đó như {1, 2, 1, 2, 3}.ContainsSubsequence({1, 2, 3})).

Đoạn mã trên hoạt động thực sự tốt cho định nghĩa phổ biến hơn về sau (nghĩa là không cần tiếp giáp) nhưng để xử lý việc cài đặt lại (hầu hết các số IEnumerators không hỗ trợ), thì chuỗi đích cần được liệt kê phía trước. Điều đó dẫn đến mã sau:

public static bool ContainsSubequence<T>(this IEnumerable<T> parent, IEnumerable<T> target) 
{ 
    bool foundOneMatch = false; 
    var enumeratedTarget = target.ToList(); 
    int enumPos = 0; 

    using (IEnumerator<T> parentEnum = parent.GetEnumerator()) 
    { 
     while (parentEnum.MoveNext()) 
     { 
      if (enumeratedTarget[enumPos].Equals(parentEnum.Current)) 
      { 
       // Match, so move the target enum forward 
       foundOneMatch = true; 
       if (enumPos == enumeratedTarget.Count - 1) 
       { 
        // We went through the entire target, so we have a match 
        return true; 
       } 

       enumPos++; 
      } 
      else if (foundOneMatch) 
      { 
       foundOneMatch = false; 
       enumPos = 0; 

       if (enumeratedTarget[enumPos].Equals(parentEnum.Current)) 
       { 
        foundOneMatch = true; 
        enumPos++; 
       } 
      } 
     } 

     return false; 
    } 
} 

Mã này không có lỗi, nhưng sẽ không hoạt động tốt cho các chuỗi lớn (hoặc vô hạn).

+1

Bạn đã phạm sai lầm trong ví dụ của bạn? Làm thế nào là 1, 3 một chuỗi trong 1, 2, 3? Cả hai số tồn tại, nhưng không theo thứ tự. Có vẻ như phương pháp của bạn xác định liệu số tồn tại, không liên quan đến thứ tự hoặc chuỗi. –

+0

@James Như tôi đã đề cập ở phần cuối, nó cho phép các chuỗi không tiếp giáp (ví dụ, '{1, 2, 3} .ContainsSubequence ({2, 1, 3}) == false'.) Như tôi cũng đề cập đến ở cuối, điều kiện đó có thể dễ dàng áp đặt, nên điều đó được yêu cầu. Thông thường khi nói về các chuỗi, sự liền kề là * không * bắt buộc (xem, ví dụ, vấn đề sau phổ biến dài nhất.) – dlev

+0

Nó không nên cho phép các chuỗi tiếp giáp không tiếp giáp. – user906763

4

Tương tự như @ dlev của nhưng điều này cũng xử lý {1,1,1,2}.ContainsSubsequence({1,1,2})

public static bool ContainsSubsequence<T>(this IEnumerable<T> parent, IEnumerable<T> target) 
{ 
    var pattern = target.ToArray(); 
    var source = new LinkedList<T>(); 
    foreach (var element in parent) 
    { 
     source.AddLast(element); 
     if(source.Count == pattern.Length) 
     { 
      if(source.SequenceEqual(pattern)) 
       return true; 
      source.RemoveFirst(); 
     } 
    } 
    return false; 
} 
+1

+1 Làm tăng ngắn gọn, metakes, methanks ... –

+0

Một sự tinh tế quan trọng trong việc thực hiện này là nó chỉ liệt kê từng bộ sưu tập được truyền vào một lần, làm cho phương thức nội bộ nhất quán nếu nó được gọi với các bộ sưu tập có thứ tự liệt kê là không xác định. Cũng lưu ý rằng một hàng đợi có thể được sử dụng thay cho danh sách được liên kết. –

0

này làm việc cho tôi

var a1 = new List<int> { 1, 2, 3, 4, 5 }; 
var a2 = new List<int> { 2, 3, 4 }; 

int index = -1; 
bool res = a2.All(
    x => index != -1 ? (++index == a1.IndexOf(x)) : ((index = a1.IndexOf(x)) != -1) 
); 
+0

Giải pháp của bạn có vẻ thanh lịch nhất nhưng hãy thử với 'a1 = new List {1, 2, 9, 1, 2, 3, 4, 5} 'và' a2 = danh sách mới {2, 3, 4} ' thay thế; cũng thử nếu 'a1' chứa chính nó với giá trị mới này - nó không hoạt động đối với tôi. – user2341923

0

Hàm này kiểm tra liệu Danh sách parent chứa Danh sách target sử dụng một số LINQ:

public static bool ContainsSequence<T>(this List<T> parent, List<T> target) 
    { 
     for (int fromElement = parent.IndexOf(target.First()); 
      (fromElement != -1) && (fromElement <= parent.Count - target.Count); 
      fromElement = parent.FindIndex(fromElement + 1, p => p.Equals(target.First()))) 
     { 
      var comparedSequence = parent.Skip(fromElement).Take(target.Count); 
      if (comparedSequence.SequenceEqual(target)) return true; 
     } 
     return false; 
    }  
1

Nếu bạn đang xử lý đơn giản serializable loại, bạn có thể làm điều đó khá dễ dàng nếu bạn chuyển đổi các mảng chuỗi:

public static bool ContainsList<T>(this List<T> containingList, List<T> containedList) 
{ 
    string strContaining = "," + string.Join(",", containingList) + ","; 
    string strContained = "," + string.Join(",", containedList) + ","; 
    return strContaining.Contains(strContained); 
} 

Lưu ý đó là một phương pháp khuyến nông, vì vậy bạn sẽ có thể gọi nó là thích:

if (bigList.ContainsList(smallList)) 
{ 
    ... 
} 
Các vấn đề liên quan