2017-02-28 31 views
1

假设我有其他移动后的具体内容,但不是顶部或底部

{ "w", "w", "z", "a", "c", "r", "f", "d", "e", "c", "g", "f", "m", "z" } 

一个数组,我有所有“C”应为“F”之前移动的规则。 在遵守规则的前提下尽可能保持与原件最接近的顺序。 真实世界的例子是一个应用程序,它知道某个插件“A”应该比载入列表中的某个插件“B”更高。

所以,预期的结果将是:

首架F前

移到C:

{ "w", "w", "z", "a", "c", "r", "c"<<, "f", "d", "e", "g", "f", "m", "z" } 

F移动最C后:

{ "w", "w", "z", "a", "c", "r", "d", "e", "c", >>"f", "g", "f", "m", "z" } 

是否有可能使用LINQ或任何准备好这样的目的?

我试过OrderBy(x => x == "c" ? 0 : x == "f" ? 1 : (int?)null),但它将元素移动到了最后。我想只对特定元素进行排序,但在可能的情况下保持其相对于其他元素的位置。

UPDATE

该解决方案应该对任何输入工作:

public static char GetLetter(Random rand) 
    { 
     string chars = "abcdefghijklmnopqrstuvwxyz"; 
     int num = rand.Next(0, chars.Length - 1); 
     return chars[num]; 
    } 

    public static IEnumerable<string> Sort(IEnumerable<string> enumerable, string first, string second) 
    { 
     ??? 

    } 

    static void Main(string[] args) 
    { 
     Random rand = new Random(); 
     string[] input = Enumerable.Range(1, 10).Select(x => GetLetter(rand) + "").ToArray(); 
     var result = Sort(Sort(input, "c", "f"), "m", "e"); 
    } 

支持多个元素( “M”, “C”, “F”)和多个规则是可取的,如果它不事情太复杂了。

+0

是否可以使用'List '而不是?这允许你在指定的索引处插入/删除,这使得这更容易。它可以用数组完成,但比一行LINQ更难。 – Equalsk

+0

这是发生在内存中还是LINQ被转换成SQL? –

+0

@RobLang在内存中 – Vlad

回答

2

这种方法你想要做什么:

public static IEnumerable<string> Sort(this IEnumerable<string> enumerable, string first, string second) 
{ 
    return enumerable.TakeWhile(s => s != second) 
     .Concat(enumerable.SkipWhile(s => s != second).OrderBy(a => a != first)); 
} 

的想法是,第一列表的一部分取,直到第一个f(在这种情况下)。然后将其余部分追加到它,首先按c个字符排序。

缺点是该列表枚举两次(部分)。如果这对性能至关重要,您应该选择只枚举一次的替代方案。

1

这是一个解决方案:

string[] ch = {"a", "c", "f", "d", "e", "c", "g", "f", "m"}; 
var res = ch.Select((item, index) => new { item, index }) 
      .OrderBy(x => x.item == "c" ? 0 : Convert.ToInt32(x.index)) 
      .Select(c => c.item).ToArray(); 

输出:

enter image description here

+0

您的解决方案适合这种情况具体的输入,但你如何指定“f”?如果以后我想排序“c”和“g”?您仅在此处对“c”进行排序。 – Vlad

+0

@Vlad它的工作原理基于你的规则:*和我有一个规则,所有的“c”应该在“f”之前移动*所以它不关心f或g或.....它首先对'c'字符进行排序,并始终产生您在问题中显示的第一个预期结果,无论是“f”还是“g”或.... –

+0

您坚持特定的输入。规则是*所有“c”应该在“f”之前移动*,我需要能够将它应用到任何元素数组,而不仅仅是这个*“a”,“c”,“f”,“d” ,“e”,“c”,“g”,“f”,“m”*。 – Vlad

0

如果理解你的问题正确,我认为你需要有将在其中定义的规则阵列规则喜欢哪个角色应该先来。在这里,我正在考虑考虑你的老年人。您可以修改规则并使用它。

[Test] 
    public void CustomOrderByTests() 
    { 
     char[] ch = { 'a', 'c', 'f', 'd', 'e', 'c', 'g', 'f', 'm' }; 
     char[] rules = { 'a', 'f', 'c' }; 

     var result = rules.Intersect(ch).Union(ch); 

     char[] expected = { 'a', 'f', 'c', 'd', 'e', 'g', 'm' }; 
     CollectionAssert.AreEqual(result, expected); 
    } 

如果你想使用前Array.Sort()超载在同一位置重复的元素,它将短的结果,而不删除重复项

Array.Sort(rules, ch); 

现在你ch阵列将已经整理阵列。

+0

1.输出包含另一个不是预期的元素数量。这只是将他们全部移到序列的开头。但是在开始时可能还有其他因素,应该保留哪些位置。如果我有*'x',r,z,a,c,f,d,e,c,g,f, M'*?我编辑了这个问题。 – Vlad

+0

1.什么元素数量? 2.如果你有另一个元素,将它添加到规则数组中的正确位置。 –

+0

有9个元素,你的输出是7个元素。 – Vlad

相关问题