2013-08-04 51 views

Trả lời

19

Vâng đơn giản - nhưng không hiệu quả - cách sẽ là:

var result = _lstNeedToOrder.OrderBy(x => _lstOrdered.IndexOf(x)); 

Một thay thế sẽ được làm việc ra một cách xa có được chỉ số mong muốn của một giá trị. Nếu giá trị của bạn luôn nằm trong phạm vi [1 ... n], bạn có thể đảo ngược danh sách "đã sắp xếp" đó thành "danh sách chỉ mục theo giá trị". Lúc này bạn có thể sử dụng:

var result = _lstNeedToOrder.OrderBy(x => indexes[x]); 

(nơi indexes sẽ có một giá trị thêm vào lúc bắt đầu cho 0, chỉ để làm cho mọi việc đơn giản hơn).

Hoặc, bạn có thể tạo Dictionary<int, int> từ giá trị đến chỉ mục. Đó sẽ là tổng quát hơn, trong đó nó sẽ xử lý một phạm vi rất rộng các giá trị mà không cần tốn nhiều bộ nhớ. Nhưng tra cứu từ điển rõ ràng là kém hiệu quả hơn so với tra cứu mảng hoặc danh sách.

Cũng giống như một lưu ý bên đó sẽ không định dạng cũng như nhận xét, khởi tạo của bạn có thể được đơn giản hóa bằng cách sử dụng khởi tạo bộ sưu tập:

var listToOrder = new List<int> { 1, 5, 6, 8 }; 
var orderedList = new List<int> { 13, 5, 11, 1, 4, 9, 2, 7, 12, 10, 3, 8, 6 }; 
+0

Xin chào Jon, xin lỗi Nếu đó là câu hỏi ngớ ngẩn, nhưng tại sao câu hỏi không hiệu quả đầu tiên? –

+1

@DimitarDimitrov: Nó sử dụng 'IndexOf' để tìm chỉ mục mong muốn của mỗi mục nhập. Đó là một hoạt động O (n) trên kích thước của '_lstOrdered', không cần thiết. –

+0

@DimitarDimitrov có thể vì sử dụng 'IndexOf'? –

13
List<int> results = _lstOrdered.Where(item => _lstNeedToOrder.Contains(item)).ToList(); 
+0

Ý tưởng thú vị. Nó sẽ không xử lý các bản sao, nhưng chúng tôi không biết liệu nó có cần thiết hay không. –

+0

Hm, tôi đã không nghĩ đến trường hợp đó. :) Tôi đoán nó lên đến OP cho dù đó là trong các yêu cầu hay không. –

+0

@VaughanHilts, sẽ không có bản sao trong trường hợp của tôi, Cảm ơn! –

1

tiết kiệm trong một từ điển trung gian thứ tự ...

// dict key will be the values of _lstOrdered, value will be the index of the 
// key in _lstOrdered 
// I'm using a seldom used .Select overload that returns the current value 
// plus its index (ix) 
var dict = _lstOrdered.Select((p, ix) => new { Value = p, Ix = ix }) 
         .ToDictionary(p => p.Value, p => p.Ix); 

// note that this will explode if _lstNeedToOrder contains values outside 
// _lstOrdered. 
_lstNeedToOrder.Sort((p, q) => dict[p] - dict[q]); 

Các .Sort cả các loại phương pháp tại chỗ để _lstNeedToOrder sẽ được đặt hàng.

4

Bạn có thể xây dựng một comparer tùy chỉnh như thế này:

public class SequenceComparer<T> : IComparer<T> { 
    private readonly Dictionary<T, int> indexes; 

    public SequenceComparer(IEnumerable<T> sequence) { 
     this.indexes = 
      sequence 
       .Select((item, index) => new { Item = item, Index = index }) 
       .ToDictionary(x => x.Item, x => x.Index); 
    } 

    public int Compare(T x, T y) { 
     return indexes[x].CompareTo(indexes[y]); 
    } 
} 

Bây giờ bạn có thể nói

var result = _lstNeedToOrder.OrderBy(x => x, new SequenceComparer(_lstOrdered)); 
+0

cách sử dụng lớp 'SequenceComparer ', tôi không thấy cách nó được sử dụng trong truy vấn 'OrderBy'. –

+1

@King King: Cảm ơn. Tôi đã bỏ lỡ việc tạo nó trong cuộc gọi đến 'OrderBy'. Nó đang ở đó. Cảm ơn một lần nữa. – jason

4

này hoạt động khá tốt:

var lookup = _lstOrdered 
    .Select((x, n) => new { x, n }) 
    .ToLookup(x => x.x, x => x.n); 

var query = 
    from x in _lstNeedToOrder 
    let rank = lookup[x] 
     .DefaultIfEmpty(int.MaxValue) 
     .First() 
    orderby rank 
    select x; 
2

Một lựa chọn khác là sử dụng Intersect, đảm bảo trả về các phần tử theo thứ tự xuất hiện trong chuỗi đầu tiên.

Vì vậy, trong ví dụ này

var result = _lstOrdered.Intersect(_lstNeedToOrder); 

mang { 5, 1, 8, 6} theo yêu cầu.

Các vấn đề liên quan