通过 Linq 找到给定对象的 2 个邻居

本文关键字:邻居 对象 Linq 通过 | 更新日期: 2023-09-27 17:57:02

我有一个对象列表,例如,

List<Person> list = new List<Person>
{
    new Person { Name = "John", Age = 24 }, 
    new Person { Name = "Tom", Age = 35 },
    new Person { Name = "Mike", Age = 42 },
    new Person { Name = "Steve", Age = 51 }
}

还有一个人,说{Phil, 45}.

我想在列表中找到我们的 2 个人,这使得给定人的年龄介于他们之间。在我们的例子中,他们是迈克和史蒂夫。

我可以使用内置的 Linq 扩展执行此操作吗?

通过 Linq 找到给定对象的 2 个邻居

如果您愿意在两次迭代中执行此操作,则

很容易做到这一点:
var sortedList = list.OrderBy(p => p.Age);    // Only if not already sorted
var searchPerson = new Person { Name = "Phil", Age = 45 };
var prevPerson = sortedList.LastOrDefault(p => p.Age < searchPerson.Age);
var nextPerson = sortedList.FirstOrDefault(p => p.Age > searchPerson.Age);

但是,我必须告诉您,这真的不是 Linq 扩展的工作。 忘掉林克吧。

如果您确实有问题中指定的List<T>,那么您可以使用List<T>.BinarySearch方法。 如果您正在处理纯(不可索引)IEnumerable<T>实例,则只需迭代它:

Person searchPerson = ...
Person previousPerson = null;
Person nextPerson = null;
foreach (var p in list.OrderBy(p => p.Age))
{
    if (p.Age < searchPerson.Age)
        previousPerson = p;
    else
    {
        nextPerson = p;
        break;
    }
}

这将在一次迭代中获得结果,并且只扫描年龄较高的第一个Person序列,而不是扫描到最后。

效率不是很高,但你可以做到

var orderedList = list.OrderBy(p => p.Age);
var neighbors  = new List<Person> 
                  {orderedList .FirstOrDefault(p => p.Age > phil.Age),
                          orderedList.LastOrDefault(p => p.Age < phil.Age)};

我会做这样的事情:

Person p = new Person("Phil", 45);
List<Person> sList = (from Person x in list orderby x.Age - p.Age select x).ToList();
for(int i = 0; i < sList.Count - 1; i++) {
    if(sList[i] < 0 && sList[i + 1] > 0) {
        // Found the two people - the person's age is between sList[i] and sList[i + 1]
        break;
    }
}
class Program
{
    static void Main()
    {
        List<Person> persons = new List<Person>
                                {
                                    new Person {Name = "John", Age = 24},
                                    new Person {Name = "Tom", Age = 35},
                                    new Person {Name = "Mike", Age = 42},
                                    new Person {Name = "Steve", Age = 51}
                                };

        //{Phil, 45}

        persons.Between(age: 45);

    }
}
public static class AgeExtensionMethod
{
    public static Person[] Between(this List<Person> person,int age)
    {
        var orderdList = person.OrderBy(p => p.Age);
        var k = orderdList.Where(p => p.Age < age).Last();
        var s = orderdList.Where(p => p.Age > age).First();
        return new[] {k, s};
    }
}

不确定这是否是更好的方法。

乱,但都是linq:

class Person {
    public string Name { get; set; }
    public int Age { get; set; }
    public override string ToString() {
        return string.Format("{0} {1}", Name, Age);
    }
}
class Program {
    static void Main(string[] args) {
        List<Person> list = new List<Person>
        {
            new Person { Name = "John", Age = 24 }, 
            new Person { Name = "Tom", Age = 35 },
            new Person { Name = "Mike", Age = 42 },
            new Person { Name = "Steve", Age = 51 }
        };
        var phil = new Person { Name = "Phil", Age = 45 };
        var findTwo = list.OrderBy(p => p.Age).Reverse().SkipWhile(p => p.Age > phil.Age).Take(1).Concat(list.OrderBy(p => p.Age).SkipWhile(p => p.Age < phil.Age).Take(1));
        foreach(var person in findTwo) {
            Console.WriteLine(person);
        }
        Console.WriteLine("DONE");
        Console.ReadLine();
    }
}

List<Person> list = new List<Person>
{
    new Person { Name = "John", Age = 24 }, 
    new Person { Name = "Tom", Age = 35 },
    new Person { Name = "Mike", Age = 42 },
    new Person { Name = "Steve", Age = 51 }
};
var phil = new Person { Name = "Phil", Age = 45 };
var twoNearest = from p2 in
                (from p1 in list
                where p1.Age > phil.Age || p1.Age < phil.Age
                select new {
                    Name = p1.Name,
                    Age = p1.Age,
                    Younger = p1.Age < phil.Age
                })
            group p2 by p2.Younger into split
            from p in split
            where (p.Age == split.Max(a => a.Age) && p.Younger) || (p.Age == split.Min(a => a.Age) && !p.Younger)
            select new Person {
                Name = p.Name,
                Age = p.Age,
            };