C#根据另一个数组对数组的一部分进行排序

C# sorting part of an array based on another array

我有一个 class 数组代表一个用户,另一个 class 数组代表固定的项目(目前只有用户 ID)。这是 classes:

public class User
{
    public int UserId { get; set; }
    public bool Pinned { get; set; }

    public User(int userId, bool pinned)
    {
        UserId = userId;
        Pinned = pinned;
    }
}

public class PinnedItem
{
    public int UserId { get; set; }

    public PinnedItem(int userId)
    {
        UserId = userId;
    }
}

固定用户的所有用户 ID 都按特定顺序(固定项目的顺序)保存,我想对用户数组进行排序,以便固定用户位于顶部,那些固定用户遵循固定项目数组的顺序.因此,例如,如果我有一组用户,例如:

var users = new []{ new User(1, true), new User(2, false), new User(3, true) }

和一个固定的项目数组,如下所示:

var pinnedItems = new [] { new PinnedItem(3), new PinnedItem(1) }

然后我希望生成的数组如下所示:

[ {3, true}, {1, true}, {2, false} ]

如果固定项目数组没有任何顺序,我也需要它工作。所以如果我有这个用户数组:

var users = new []{ new User(1, false), new User(2, true), new User(3, true), new User(4, true) }

和这个固定项目数组:

var pinnedItems = new [] { new PinnedItem(3), new PinnedItem(2), new PinnedItem(4) }

在这种情况下,我希望生成的数组如下所示:

[ {3, true}, {2, true}, {4, true}, {1, false} ]

非常感谢任何形式的帮助。另外,如果问题中有任何不清楚的地方,我很抱歉,如果需要,将相应地进行编辑。

我确信有很多方法可以做到这一点,我还有很多 LINQ 需要学习,但以下内容应该可以帮助您入门;

// First, get the users that are mentioned by a PinnedItem 
var pinnedUsers = pinnedItems.Select(x => users.FirstOrDefault(y => y.UserId == x.UserId));
// Get all the users that are not mentioned in a PinnedItem
var unpinnedUsers = users.Except(pinnedUsers);
// Combine both
var both = pinnedUsers.Concat(unpinnedUsers);

有点邋遢,但这样就可以了:

var joined = 
   users
      .GroupJoin(pinnedItems, u => u.UserId, p => p.UserId, (u, p) => new { u.UserId, Pinned = p.Any() })
      .OrderByDescending(r => r.Pinned)
      .ThenByDescending(r => r.UserId)
      .ToList();

您可以调整投影和排序以获得您想要的效果。

这是我的导师想出的针对更大数组优化的解决方案,如果有人偶然发现这个 post(@Fixation post 编辑的答案完全没问题,如果你知道的话不会有很多固定项目):

Dictionary<int, int?> positionByUserId = pinnedItems
        .Select((i, index) => new { i.UserId, Position = index })
        .ToDictionary(x => x.UserId, x => (int?)x.Position);

var result = users
        .Select(u => new
        {
            User = u,
            Position = positionByUserId.GetValueOrDefault(u.UserId) ?? int.MaxValue
        })
        .OrderBy(x => x.Position)
        .Select(x => x.User)
        .ToArray();