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();
我有一个 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();