将一个foreach链用于将列表中的元素插入到linq的另一个列表中

时间:2013-08-22 19:42:58

标签: c# linq list foreach

我已经在这里工作了几个小时,我取得的唯一结论就是我需要拿一本关于Linq的好书。

所以这是交易:我有以下类的三个对象列表(从现在开始我将它们称为“父列表”:

    public class State
    {
        public int IdState {get; set;}
        public string NameState {get; set;}
        private IList<City> cityList = new List<City>();

        public void AddCity(City city)
        {
            cityList.Add(city);
        }
    }

    public class City
    {
        public int IdCity { get; set; }
        public string NameCity { get; set; }
        public int IdState { get; set; }
        private IList<Company> companyList = new List<Company>();

        public void AddCompany(Company company)
        {
            companyList.Add(company);
        }
    }

    public class Company
    {
        public int IdCompany { get; set; }
        public string NameCompany { get; set; }
        public int IdCity { get; set; }
    }

我认为从这里可以很简单地解释我想要的东西:一个州的单一列表,其中cityList填充了该州的相应城市,每个城市中的每个公司列表列表都填充了该城市的公司。换句话说,每个州分支到其城市的州的列表,然后每个城市分支到其中的公司。

所以,我的父母名单是:

    private List<State> finalList; //This is the "parent list supreme" which I'll send to the client-side
    private List<City> cityList; //Auxiliary
    private List<Company> companyList; //Auxiliary; this one does not exist in the actual code but I'm putting it here for simplification purposes

真的无关紧要但是由于linq“魔术”,我能够用适当的州,城市和公司填写这些名单,但是,我无法弄清楚如何填写正确的城市和公司通过链接进入State.cityList和City.companyList。就目前而言,我正在使用一条非常丑陋的foreach链:

        foreach (State state in finalList)
        {
            foreach (City city in cityList)
            {
                if (city.IdState == state.IdState)
                {
                    state.AddCity(city);

                    foreach (Company company in companyList)
                    {
                        if (company.idCity == city.IdCity)
                            city.AddCompany(company);
                    }
                }
            }
        }

丑陋,对吗?那么,我如何用linq实现同样的目标呢?我想也许是一个更有效的问题:在这种情况下是否值得使用linq(它都指向“是”但数字......)?

顺便说一句:这种方式就像我期望的那样工作

3 个答案:

答案 0 :(得分:2)

您在这里逻辑上做的是加入操作。您当前的代码实际上是查找所有可能的城市和州对,然后仅归档匹配的对。您可以在LINQ中表示,但您不希望这样。有更有效的方法来执行Join,它只生成您需要的精确对。 LINQ Join运算符利用了这一点。

您的代码归结为两个不同的Join调用,然后对每个结果进行迭代,根据查询执行对象的变异。

var stateCityPairs = from state in finalList
                        join city in cityList
                        on state.IdState equals city.IdState
                        select new { state, city };

foreach (var pair in stateCityPairs)
    pair.state.AddCity(pair.city);


var cityCompanyPairs = from city in cityList
                        join company in companyList
                        on city.IdCity equals company.IdCity
                        select new { city, company };

foreach (var pair in cityCompanyPairs)
    pair.city.AddCompany(pair.company);

虽然这实际上是一个更多的代码,但对于更大的集合,这将表现得更好,并且在语义上也代表了代码的意图。

答案 1 :(得分:0)

使用LINQ,您可能希望将私有IList转换为公共IList(或列表或IEnumerable或IQueryable),以便您可以直接设置它们。

假设finalList已预先填入状态:

var finalList=finalList
    .Select(fl=>new State
    {
        fl.IdState,
        fl.NameState,
        cityList=cityList.Where(cl=>cl.IdState==fl.IdState).Select(cl=>
            new City
            {
                cl.IdCity,
                cl.NameCity,
                cl.IdState,
                companyList=companyList.Where(comp=>
                    comp.IdState==cl.IdState && comp.IdCity==cl.IdCity)
            }
    });

答案 2 :(得分:0)

我在City和State类中添加了2个方法。如果列表是公开的,那会更容易:

public void AddCities(List<City> cities)
{
    cityList.Concat(cities);
}

public void AddCompanies(List<Company> companies)
{
    companyList.Concat(companies);
}

您可以使用所需的聚合器。我通常更喜欢Union,因为它不会增加双打,但我想在你的情况下这并不重要。

她是如何在Linq中做到的:

cityList.ForEach(ci => ci.AddCompanies(companyList.Where(co => co.IdCity == ci.IdCity).ToList()));
finalList.ForEach(s => s.AddCities(cityList.Where(ci => ci.IdState == s.IdState).ToList()));

我首先将公司添加到适当的城市,然后我将所有城市添加到正确的状态。 如果您需要有关此代码的更多说明,请随时提问。