将特定元素移到其他元素之后但不移到顶部或底部

时间:2017-02-28 11:40:33

标签: c# linq sorting

假设我有一个

数组
{ "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" }

在最后一个c:

之后移动了f
{ "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),但它将元素移到了最后。我想只对彼此的特定元素进行排序,但在可能的情况下保持其相对于其他元素的位置。

更新

解决方案适用于任何输入:

    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");
    }

支持多个元素(&#34; m&#34;,&#34; c&#34;,&#34; f&#34;)和多个规则是理想的,如果它不会使事情复杂化太多

3 个答案:

答案 0 :(得分: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 :(得分: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

答案 2 :(得分:-1)

如果在正确理解你的问题,我认为你需要有一个数组规则,你将在其中定义规则,比如哪个字符应该首先出现。考虑到你的老年人,我在这里添加一个测试。您可以修改规则并使用它。

    [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数组将有排序数组。