在 C# 中按类型字段重新排列对象列表



我有一个传入的警报列表,我使用MapFunction作为:

private static BPAlerts MapToAlerts(List<IntakeAlert> intakeAlerts)
{
// Make sure that there are alerts
if (intakeAlerts.IsNullOrEmpty()) return new BPAlerts { AllAlerts = new List<BPAlert>(), OverviewAlerts = new List<BPAlert>() };
// All Alerts
var alerts = new BPAlerts
{
AllAlerts = intakeAlerts.Select(
alert => new BPAlert
{
AlertTypeId = alert.AlertTypeId ?? 8100,
IsOverview = alert.IsOverviewAlert.GetValueOrDefault(),
Text = alert.AlertText,
Title = alert.AlertTitle,
Type = alert.AlertTypeId == 8106 ? "warning" : "report",
Severity = alert.AlertSeverity.GetValueOrDefault(),
Position = alert.Position.GetValueOrDefault()
}).OrderBy(a => a.Position).ToList()
};

// Alerts displayed on the overview page
alerts.OverviewAlerts =
alerts.AllAlerts
.ToList()
.Where(a => a.IsOverview && !string.IsNullOrEmpty(a.Title))
.Take(3)
.ToList();
return alerts;
}

BPAlerts 类型包含两种类型的列表:

public class BPAlerts
{
public List<BPAlert> AllAlerts { get; set; }
public List<BPAlert> OverviewAlerts { get; set; }
}

BPAlert 类型定义为:

public class BPAlert
{
public short AlertTypeId { get; set; }
public string Type { get; set; }
public int Severity { get; set; }
public bool IsOverview { get; set; }
public string Title { get; set; }
public string Text { get; set; }
public int Position { get; set; }
public string Id { get; internal set; } = Guid.NewGuid().ToString();
}

我想实现一个任务,其中 MaptoAlerts 函数返回一个带有概述警报的警报对象,这些警报根据 BPAlert 的类型进行排序。如果存在,请按以下顺序更清楚:

已确认停业 - 8106 破产 - 8105 缺少许可 - 8111 调查 - 8109 政府行动 - 8103 投诉模式 - 8104 客户评论 - 8112 认证 - 8110 误用 BBB 名称 - 8101 警告 - 8107 广告评论 – 8102

解决方案 #1 订单值数组

我只是在某种集合中定义这些 id 的顺序,可以是数组:

var orderArray = new int[]
{
8106,   // Confirmed Out of Busine
8105,   // Bankruptcy
8111,   // Lack of Licensing
8109,   // Investigations
8103,   // Government Actions
8104,   // Pattern of Complaints
8112,   // Customer Reviews
8110,   // Accreditation
8101,   // Misuse of BBB Name
8107,   // Advisory
8102,   // Advertising Review
};

然后在增加订单值的同时遍历数组。循环检查订单数组是否包含我正在尝试评估的订单值的实际类型 id:

for (int orderValue = 0; orderValue < orderArray.Length; orderValue++)
{
if (alertTypeId == orderArray[orderValue])
{
return orderValue;
}
}

如果在数组中找不到,则返回可能的最高值:

return int.MaxValue

整个方法如下所示,它将评估警报类型 ID 的顺序:

public int GetAlertTypeIdOrder(short alertTypeId)
{
var orderArray = new int[]
{
8106,   // Confirmed Out of Busine
8105,   // Bankruptcy
8111,   // Lack of Licensing
8109,   // Investigations
8103,   // Government Actions
8104,   // Pattern of Complaints
8112,   // Customer Reviews
8110,   // Accreditation
8101,   // Misuse of BBB Name
8107,   // Advisory
8102,   // Advertising Review
};
for (int orderValue = 0; orderValue < orderArray.Length; orderValue++)
{
if (alertTypeId == orderArray[orderValue])
{
return orderValue;
}
}
return int.MaxValue;
}

用法:

var sortedAlerts = alerts
.AllAlerts
.OrderByDescending(a => GetAlertTypeIdOrder(a.AlertTypeId))
.ToList();

它也以降序方式工作。

解决方案#2订单值字典

您可以通过减少冗余(重复创建存储订单值的数组(来实现更好的性能。更好的主意是将顺序规则存储在字典中。我知道下面的代码也创建了一个数组,但这个概念是它会被调用一次以获取字典,然后传递字典。

public Dictionary<int, int> GetOrderRules()
{
var alertTypeIds = new int[]
{
8106,   // Confirmed Out of Busine
8105,   // Bankruptcy
8111,   // Lack of Licensing
8109,   // Investigations
8103,   // Government Actions
8104,   // Pattern of Complaints
8112,   // Customer Reviews
8110,   // Accreditation
8101,   // Misuse of BBB Name
8107,   // Advisory
8102,   // Advertising Review
};
var orderRules = new Dictionary<int, int>();
for (int orderValue = 0; orderValue < alertTypeIds.Length; orderValue++)
{
orderRules.Add(alertTypeIds[orderValue], orderValue);
}
return orderRules;
}

因此,GetAlertIdOrder()方法看起来会有所不同,但仍保留了先前解决方案的想法:

public int GetAlertIdOrder(short alertTypeId, IDictionary<int, int> orderRules)
{
if (orderRules.TryGetValue(alertTypeId, out int orderValue))
{
return orderValue;
}
else
{
return int.MaxValue;
}
}

用法:

var orderRules = GetOrderRules();
var sortedAlerts = alerts
.AllAlerts
.OrderBy(a => GetAlertIdOrder(a.AlertTypeId, orderRules))
.ToList();

(a( 我不会将排序与映射器混为一谈。 让映射器做它的事情。(这是关注点分离(。又名,没有排序/排序。 恕我直言,您最终总是会在映射器中得到太多难以理解的巫毒教。 使用上述代码,您已经走上了这条路径。

(b( 如果"OverviewAlerts"是 AllAlerts 的子集(又名 AllAlerts 是超集(,则冻结 AllAlerts,并创建一个只读的"get"属性,您可以在其中按其规则将 AllAlerts 过滤到您的子集。 (可选(考虑 AllAlertsSort get 属性。 这样,您可以让您的消费者选择他们想要原始还是分类......因为排序是有成本的。

public class BPAlerts
{
public List<BPAlert> AllAlerts { get; set; }
public List<BPAlert> OverviewAlerts {
get
{
return null == this.AllAlerts ? null : this.AllAlerts.Where (do you filtering and maybe sorting here ) ; 
} 
}
}
public List<BPAlert> AllAlertsSorted{
get
{
return null == this.AllAlerts ? null : this.AllAlerts.Sort(do you filtering and maybe sorting here ) ; 
} 
}
}

如果执行只读属性,则具有更简单的 LINQ 操作,例如

OrderBy(x => x.PropertyAbc).ThenByDescending(x => x.PropertyDef);

我 99% 的映射代码看起来像这样。 如果您给出空输入,我什至不会抛出错误,我只是返回空。

public static class MyObjectMapper {
public static ICollection < MyOtherObject > ConvertToMyOtherObject(ICollection <MyObjectMapper> inputItems) {
ICollection <MyOtherObject> returnItems = null;
if (null != inputItems) {
returnItems = new List <MyOtherObject> ();
foreach(MyObjectMapper inputItem in inputItems) {
MyOtherObject moo = new MyOtherObject();
/* map here */
returnItems.Add(moo);
}
}
return returnItems;
}
}

最新更新