c# - 为相同类型的一对(循环列表)在轮播列表中查找不同类型的邻居

标签 c# algorithm list logic enumeration

我有一个行为类似于旋转木马的集合,即:最后一项之后是第一项。在这个集合(List of IdentifiedAnimal)中,有一对总是在一起的值(哺乳动物)。他们甚至可以是第一个和最后一个。

我的目标是找到不是该对中另一项(其他哺乳动物)的一项(作为参数传递)的最近邻居。即:如果我通过 Dog,则它不能是 Cat,反之亦然。

目前我的算法似乎运行良好,但可能存在错误。几乎所有案例的测试都通过了。尽管如此,我想知道是否有更好、更安全的方法来找到给定条件下的邻居,而不涉及如此复杂的算法。对逻辑的改进也表示赞赏。 只是强调一下,狗和猫将永远在一起,彼此(哺乳动物)的邻居。

    public Animal GetClosestAnimalNotMammal(IEnumerable<IdentifiedAnimal> identifiedAnimals, Animal currentMammal)
    {
        Animal otherMammal = (currentMammal == Animal.Dog) ? Animal.Cat : Animal.Dog;

        List<IdentifiedAnimal> animalsList = identifiedAnimals.ToList();

        int currentIndex = animalsList.FindIndex(c => c.Animal == currentMammal);
        int lastIndex = animalsList.IndexOf(animalsList.LastOrDefault());

        Dictionary<IdentifiedAnimal, int> animalIndexes = animalsList
            .Where(a => a.Animal != otherMammal && a.Animal != currentMammal)
            .ToDictionary(identifiedAnimal => identifiedAnimal, identifiedAnimal => animalsList.FindIndex(x => x.Animal == identifiedAnimal.Animal));


        int closestIndex = int.MaxValue;
        int maxDistance = int.MaxValue;
        foreach (KeyValuePair<IdentifiedAnimal, int> animalIndex in animalIndexes)
        {
            int usedDistance;

            if ((animalIndex.Value + currentIndex > lastIndex) && (currentIndex - animalIndex.Value > 0) && currentIndex != lastIndex)
            {
                usedDistance = Math.Abs((animalsList.Count - (animalIndex.Value + currentIndex)) -
                                        Math.Abs(animalIndex.Value - currentIndex));
            }
            else if ((animalIndex.Value + currentIndex == lastIndex) && !(currentIndex - animalIndex.Value > 0 && currentIndex != lastIndex))
            {
                usedDistance = Math.Abs(animalsList.Count - (animalIndex.Value + currentIndex));
            }
            else
            {
                usedDistance = Math.Abs(animalIndex.Value - currentIndex);
            }

            if (usedDistance < maxDistance)
            {
                closestIndex = animalIndex.Value;
                maxDistance = usedDistance;
            }
        }

        return animalsList[closestIndex].Animal;
    }

public enum Animal
{
    Alligator,
    Dog,
    Cat,
    Fish,
    Bird,
    Snake
}

public class IdentifiedAnimal
{
    public string Id { get; set; }
    public Animal Animal { get; set; }
}

测试

[TestClass]
public class UnitTest1
{
    private readonly List<IdentifiedAnimal> _identifiedAnimals = new List<IdentifiedAnimal>();

    [TestMethod]
    public void TestMethod01()
    {
        // Arrange
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "KLD", Animal = Animal.Alligator});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "XYZ", Animal = Animal.Dog});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "ASO", Animal = Animal.Cat});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "LOL", Animal = Animal.Fish});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "KJL", Animal = Animal.Bird});
        _identifiedAnimals.Add(new IdentifiedAnimal() { Id = "QPO", Animal = Animal.Snake });
        var expectedAnimal = Animal.Fish;

        // Act
        var closestAnimal = new AnimalFinder().GetClosestAnimalNotMammal(_identifiedAnimals, Animal.Cat);

        // Assert
        Assert.AreEqual(expectedAnimal, closestAnimal);

    }

    [TestMethod]
    public void TestMethod02()
    {
        // Arrange
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "KLD", Animal = Animal.Alligator});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "XYZ", Animal = Animal.Dog});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "ASO", Animal = Animal.Cat});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "LOL", Animal = Animal.Fish});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "KJL", Animal = Animal.Bird});
        _identifiedAnimals.Add(new IdentifiedAnimal() { Id = "QPO", Animal = Animal.Snake });
        var expectedAnimal = Animal.Alligator;

        // Act
        var closestAnimal = new AnimalFinder().GetClosestAnimalNotMammal(_identifiedAnimals, Animal.Dog);

        // Assert
        Assert.AreEqual(expectedAnimal, closestAnimal);

    }

    [TestMethod]
    public void TestMethod03()
    {
        // Arrange
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "KLD", Animal = Animal.Alligator});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "LOL", Animal = Animal.Fish});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "KJL", Animal = Animal.Bird});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "XYZ", Animal = Animal.Dog});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "ASO", Animal = Animal.Cat});
        _identifiedAnimals.Add(new IdentifiedAnimal() { Id = "QPO", Animal = Animal.Snake });
        var expectedAnimal = Animal.Bird;

        // Act
        var closestAnimal = new AnimalFinder().GetClosestAnimalNotMammal(_identifiedAnimals, Animal.Dog);

        // Assert
        Assert.AreEqual(expectedAnimal, closestAnimal);

    }

    [TestMethod]
    public void TestMethod04()
    {
        // Arrange
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "KLD", Animal = Animal.Alligator});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "LOL", Animal = Animal.Fish});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "KJL", Animal = Animal.Bird});
        _identifiedAnimals.Add(new IdentifiedAnimal() { Id = "QPO", Animal = Animal.Snake });
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "XYZ", Animal = Animal.Dog});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "ASO", Animal = Animal.Cat});
        var expectedAnimal = Animal.Alligator;

        // Act
        var closestAnimal = new AnimalFinder().GetClosestAnimalNotMammal(_identifiedAnimals, Animal.Cat);

        // Assert
        Assert.AreEqual(expectedAnimal, closestAnimal);

    }

    [TestMethod]
    public void TestMethod05()
    {
        // Arrange
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "XYZ", Animal = Animal.Dog});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "ASO", Animal = Animal.Cat});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "KLD", Animal = Animal.Alligator});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "LOL", Animal = Animal.Fish});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "KJL", Animal = Animal.Bird});
        _identifiedAnimals.Add(new IdentifiedAnimal() { Id = "QPO", Animal = Animal.Snake });
        var expectedAnimal = Animal.Snake;

        // Act
        var closestAnimal = new AnimalFinder().GetClosestAnimalNotMammal(_identifiedAnimals, Animal.Dog);

        // Assert
        Assert.AreEqual(expectedAnimal, closestAnimal);

    }

    [TestMethod]
    public void TestMethod06()
    {
        // Arrange
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "KLD", Animal = Animal.Alligator});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "LOL", Animal = Animal.Fish});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "KJL", Animal = Animal.Bird});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "ASO", Animal = Animal.Cat});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "XYZ", Animal = Animal.Dog});
        _identifiedAnimals.Add(new IdentifiedAnimal() { Id = "QPO", Animal = Animal.Snake });
        var expectedAnimal = Animal.Snake;

        // Act
        var closestAnimal = new AnimalFinder().GetClosestAnimalNotMammal(_identifiedAnimals, Animal.Dog);

        // Assert
        Assert.AreEqual(expectedAnimal, closestAnimal);

    }

    [TestMethod]
    public void TestMethod07()
    {
        // Arrange
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "KLD", Animal = Animal.Alligator});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "LOL", Animal = Animal.Fish});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "ASO", Animal = Animal.Cat});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "XYZ", Animal = Animal.Dog});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "KJL", Animal = Animal.Bird});
        _identifiedAnimals.Add(new IdentifiedAnimal() { Id = "QPO", Animal = Animal.Snake });
        var expectedAnimal = Animal.Bird;

        // Act
        var closestAnimal = new AnimalFinder().GetClosestAnimalNotMammal(_identifiedAnimals, Animal.Dog);

        // Assert
        Assert.AreEqual(expectedAnimal, closestAnimal);

    }

    [TestMethod]
    public void TestMethod08()
    {
        // Arrange
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "ASO", Animal = Animal.Cat});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "KLD", Animal = Animal.Alligator});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "LOL", Animal = Animal.Fish});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "KJL", Animal = Animal.Bird});
        _identifiedAnimals.Add(new IdentifiedAnimal() { Id = "QPO", Animal = Animal.Snake });
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "XYZ", Animal = Animal.Dog});
        var expectedAnimal = Animal.Snake;

        // Act
        var closestAnimal = new AnimalFinder().GetClosestAnimalNotMammal(_identifiedAnimals, Animal.Dog);

        // Assert
        Assert.AreEqual(expectedAnimal, closestAnimal);
    }

    [TestMethod]
    public void TestMethod09()
    {
        // Arrange
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "ASO", Animal = Animal.Cat});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "KLD", Animal = Animal.Alligator});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "LOL", Animal = Animal.Fish});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "KJL", Animal = Animal.Bird});
        _identifiedAnimals.Add(new IdentifiedAnimal() { Id = "QPO", Animal = Animal.Snake });
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "XYZ", Animal = Animal.Dog});
        var expectedAnimal = Animal.Alligator;

        // Act
        var closestAnimal = new AnimalFinder().GetClosestAnimalNotMammal(_identifiedAnimals, Animal.Cat);

        // Assert
        Assert.AreEqual(expectedAnimal, closestAnimal);
    }

    [TestMethod]
    public void TestMethod10()
    {
        // Arrange
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "ASO", Animal = Animal.Cat});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "XYZ", Animal = Animal.Dog});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "KLD", Animal = Animal.Alligator});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "LOL", Animal = Animal.Fish});
        _identifiedAnimals.Add(new IdentifiedAnimal() {Id = "KJL", Animal = Animal.Bird});
        _identifiedAnimals.Add(new IdentifiedAnimal() { Id = "QPO", Animal = Animal.Snake });
        var expectedAnimal = Animal.Snake;

        // Act
        var closestAnimal = new AnimalFinder().GetClosestAnimalNotMammal(_identifiedAnimals, Animal.Cat);

        // Assert
        Assert.AreEqual(expectedAnimal, closestAnimal);
    }


}

最佳答案

没有讽刺的意思,但是,这个问题不是更容易解决吗?我很难理解为什么每个人都需要字典等。也许我误解了什么。

public static bool TryFindNearestTo<T>
    (this IList<T> source, 
     T item, 
     T itemToExcludeFromSearch, 
     out T nearest)
{
    var indexOfItem = source.IndexOf(item);

    if (indexOfItem < 0)
    {
        //item is not found in source. Search fails.
        nearest = default(T);
        return false;
    }

    var indexAfter = indexOfItem == source.Count - 1 ? 
        0 :
        indexOfItem + 1;

    var indexBefore = indexOfItem == 0 ?
        source.Count - 1 :
        indexOfItem - 1;

    //Assert preconditions
    Debug.Assert(source[indexAfter].Equals(itemToExcludeFromSearch) ||
                 source[indexBefore].Equals(itemToExcludeFromSearch));

    nearest = source[indexAfter].Equals(itemToExcludeFromSearch) ?
        source[indexBefore] :
        source[indexAfter];

    return true;
}

您当前的问题定义不完整。如果出现以下情况,该方法应该做什么:

  1. source 中找不到指定的 item
  2. 如果没有邻居将项目从搜索中排除,会发生什么情况?

如果这两种情况不可能发生,那么您应该在您的代码中断言它们,因为这是一个必须满足的先决条件,该方法才能正常工作。如果他们的条件是可能的,那么你需要验证它们并在不满足时返回一些合理的东西。就我而言,为了便于说明,我将两种情况混为一谈:

  1. TrySomething 模式,其中返回值指示搜索是否成功,结果是 out 参数,解决了第一个问题。
  2. Debug.Assert解决了后一个问题。

关于c# - 为相同类型的一对(循环列表)在轮播列表中查找不同类型的邻居,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48112516/

相关文章:

python - 有一个列表,我需要从中查找重复项

c# - 在 foreach 循环中修改列表

c# - 来自网络服务 : method not allowed 的响应

algorithm - 我可以使用什么算法来识别网页上的内容

c# - 使用 LINQ to SQL 插入数据时出错

c - 求和,数组构造和寻址的简洁二叉树

算法和数据结构 : should I study language specific books or generic books?

python - 遍历列表,比较前面的元素和后面的元素

c# - 处理从外部应用程序打开的文件以加载 WPF 应用程序?

c# - asp.net 文字不显示 <br><hr>