First, let's define a method to figure out whether a list follows another list order:
public static bool IsValidOrder<T>(this IEnumerable<T> items, IEnumerable<T> order)
{
IEnumerator<T> orderEnumerator = order.GetEnumerator();
orderEnumerator.MoveNext();
return items.All(item => orderEnumerator.ReadUntilGet(item));
}
public static bool ReadUntilGet<T>(this IEnumerator<T> enumerator, T item)
{
return enumerator.Current.Equals(item) ||
(enumerator.MoveNext() && enumerator.ReadUntilGet(item));
}
The ReadUntilGet<T>
method check if the current is equals to the T item, if it is not it moves the enumerator to the next position and calls itself recursively until it finds the T item, then it returns true. If it reaches the end of the enumerator without finding the T item, it returns false.
The LINQ All<T>
method check if all elements of a sequence satisfy a condition. Since we call the ReadUntilGet<T>
method inside the condition, it is called on each item from the list. And the enumerator moves on each new item on the list. If it return false in any of them, the All method return false.
Since the animals can contain names which string representation is not equal to a enum identifier it's better to use strings to define the order, as @Mat'sMug @Mat'sMug pointed out.
We can define the order in a list. Notice that numbers indicating the order are not needed because the order of the list is guaranteed to remain the same (the IEnumerable<T>
interface just iterates, it does not change ordering, AFAIK. At this answer this answer it's said otherwise, would you care to explain? I don't have enough reputation to comment):
public static IEnumerable<string> AnimalOrder { get; } = new List<string>
{
"Cat",
"Horse",
"Dog",
"Elephant",
"Great white shark"
};
So, your method would be:
public bool ValidateAnimalOrder(List<string> listOfAnimals)
{
return listOfAnimals.IsValidOrder(AnimalOrder);
}
Note that this method iterate just once on both lists and returns as soon as possible (because the All
method returns on the first item that doesn't match).
First, let's define a method to figure out whether a list follows another list order:
public static bool IsValidOrder<T>(this IEnumerable<T> items, IEnumerable<T> order)
{
IEnumerator<T> orderEnumerator = order.GetEnumerator();
orderEnumerator.MoveNext();
return items.All(item => orderEnumerator.ReadUntilGet(item));
}
public static bool ReadUntilGet<T>(this IEnumerator<T> enumerator, T item)
{
return enumerator.Current.Equals(item) ||
(enumerator.MoveNext() && enumerator.ReadUntilGet(item));
}
The ReadUntilGet<T>
method check if the current is equals to the T item, if it is not it moves the enumerator to the next position and calls itself recursively until it finds the T item, then it returns true. If it reaches the end of the enumerator without finding the T item, it returns false.
The LINQ All<T>
method check if all elements of a sequence satisfy a condition. Since we call the ReadUntilGet<T>
method inside the condition, it is called on each item from the list. And the enumerator moves on each new item on the list. If it return false in any of them, the All method return false.
Since the animals can contain names which string representation is not equal to a enum identifier it's better to use strings to define the order, as @Mat'sMug pointed out.
We can define the order in a list. Notice that numbers indicating the order are not needed because the order of the list is guaranteed to remain the same (the IEnumerable<T>
interface just iterates, it does not change ordering, AFAIK. At this answer it's said otherwise, would you care to explain? I don't have enough reputation to comment):
public static IEnumerable<string> AnimalOrder { get; } = new List<string>
{
"Cat",
"Horse",
"Dog",
"Elephant",
"Great white shark"
};
So, your method would be:
public bool ValidateAnimalOrder(List<string> listOfAnimals)
{
return listOfAnimals.IsValidOrder(AnimalOrder);
}
Note that this method iterate just once on both lists and returns as soon as possible (because the All
method returns on the first item that doesn't match).
First, let's define a method to figure out whether a list follows another list order:
public static bool IsValidOrder<T>(this IEnumerable<T> items, IEnumerable<T> order)
{
IEnumerator<T> orderEnumerator = order.GetEnumerator();
orderEnumerator.MoveNext();
return items.All(item => orderEnumerator.ReadUntilGet(item));
}
public static bool ReadUntilGet<T>(this IEnumerator<T> enumerator, T item)
{
return enumerator.Current.Equals(item) ||
(enumerator.MoveNext() && enumerator.ReadUntilGet(item));
}
The ReadUntilGet<T>
method check if the current is equals to the T item, if it is not it moves the enumerator to the next position and calls itself recursively until it finds the T item, then it returns true. If it reaches the end of the enumerator without finding the T item, it returns false.
The LINQ All<T>
method check if all elements of a sequence satisfy a condition. Since we call the ReadUntilGet<T>
method inside the condition, it is called on each item from the list. And the enumerator moves on each new item on the list. If it return false in any of them, the All method return false.
Since the animals can contain names which string representation is not equal to a enum identifier it's better to use strings to define the order, as @Mat'sMug pointed out.
We can define the order in a list. Notice that numbers indicating the order are not needed because the order of the list is guaranteed to remain the same (the IEnumerable<T>
interface just iterates, it does not change ordering, AFAIK. At this answer it's said otherwise, would you care to explain? I don't have enough reputation to comment):
public static IEnumerable<string> AnimalOrder { get; } = new List<string>
{
"Cat",
"Horse",
"Dog",
"Elephant",
"Great white shark"
};
So, your method would be:
public bool ValidateAnimalOrder(List<string> listOfAnimals)
{
return listOfAnimals.IsValidOrder(AnimalOrder);
}
Note that this method iterate just once on both lists and returns as soon as possible (because the All
method returns on the first item that doesn't match).
- 196
- 4
public static bool IsValidlOrder<T>IsValidOrder<T>(this IEnumerable<T> items, IEnumerable<T> order)
{
IEnumerator<T> orderEnumerationorderEnumerator = order.GetEnumerator();
orderEnumerator.MoveNext();
return items.All(item => orderEnumerationorderEnumerator.ReadUntilGet(item));
}
public static bool ReadUntilGet<T>(this IEnumerator<T> enumerator, T item)
{
return enumerator.Current.Equals(item) ||
(enumerator.MoveNext() && enumerator.ReadUntilGet(item));
}
The ReadUntilGet<T>
method movecheck if the current is equals to the T item, if it is not it moves the enumerator to the next position each time it is called,and calls itself recursively until it finds the item T item, then it returns true. If it reaches the end of the enumerator without finding the item T item, it returns false.
Then we can define a enum ofSince the animals, so we can easily add or changecontain names inwhich string representation is not equal to a enum identifier it's better to use strings to define the future:order, as @Mat'sMug pointed out.
public enum Animal
{
Cat,
Dog,
Horse,
Elephant,
Fish,
Koala,
Deer
}
This enum contains all the possible options, notWe can define the actual order. The order itself is defined in a list. Notice that numbers indicating the order are not needed because the order of the list is guaranteed to remain the same (the IEnumerable<T>
interface just iterates, it does not change ordering, AFAIK. At this answer it's said otherwise, would you care to explain? I don't have enough reputation to comment):
public static IEnumerable<Animal>IEnumerable<string> AnimalOrder { get; } = new List<Animal>List<string>
{
Animal.Cat"Cat",
Animal.Horse"Horse",
Animal.Dog"Dog",
Animal.Elephant
};
So, your method would be:
public bool ValidateAnimalOrder(List<Animal> listOfAnimals)
{
return listOfAnimals.IsValidlOrder(AnimalOrder);
}
But wait, your method receive a list of strings, not animals! It would probably be a better design to receive a list of animals, but if you cant change that, you can parse this list into an animals list:
public static IEnumerable<T> AsEnum<T>(this IEnumerable<string> items)
where T : struct
{
return items.Select(s =>
{
T enumType;
if (Enum.TryParse(s"Elephant", out enumType))
return enumType;
else
throw new InvalidCastException($"{s} is not"Great anwhite {typeof(T)}!");shark"
});
}
ThenSo, your method would be:
public bool ValidateAnimalOrder(List<string> listOfAnimals)
{
return listOfAnimals.AsEnum<Animal>().IsValidlOrderIsValidOrder(AnimalOrder);
}
Note that this method iterate just once on the listboth lists and returns as soon as possible (because the All
method returns on the first item that doesn't match, and the Select
method is executed just when it is needed by the iteration).
public static bool IsValidlOrder<T>(this IEnumerable<T> items, IEnumerable<T> order)
{
IEnumerator<T> orderEnumeration = order.GetEnumerator();
return items.All(item => orderEnumeration.ReadUntilGet(item));
}
public static bool ReadUntilGet<T>(this IEnumerator<T> enumerator, T item)
{
return enumerator.Current.Equals(item) ||
(enumerator.MoveNext() && enumerator.ReadUntilGet(item));
}
The ReadUntilGet<T>
method move the enumerator to the next position each time it is called, until it finds the item T, then it returns true. If it reaches the end of the enumerator without finding the item T, it returns false.
Then we can define a enum of animals, so we can easily add or change names in the future:
public enum Animal
{
Cat,
Dog,
Horse,
Elephant,
Fish,
Koala,
Deer
}
This enum contains all the possible options, not the actual order. The order itself is defined in a list. Notice that numbers indicating the order are not needed because the order of the list is guaranteed to remain the same (the IEnumerable<T>
interface just iterates, it does not change ordering):
public static IEnumerable<Animal> AnimalOrder { get; } = new List<Animal>
{
Animal.Cat,
Animal.Horse,
Animal.Dog,
Animal.Elephant
};
So, your method would be:
public bool ValidateAnimalOrder(List<Animal> listOfAnimals)
{
return listOfAnimals.IsValidlOrder(AnimalOrder);
}
But wait, your method receive a list of strings, not animals! It would probably be a better design to receive a list of animals, but if you cant change that, you can parse this list into an animals list:
public static IEnumerable<T> AsEnum<T>(this IEnumerable<string> items)
where T : struct
{
return items.Select(s =>
{
T enumType;
if (Enum.TryParse(s, out enumType))
return enumType;
else
throw new InvalidCastException($"{s} is not an {typeof(T)}!");
});
}
Then, your method would be:
public bool ValidateAnimalOrder(List<string> listOfAnimals)
{
return listOfAnimals.AsEnum<Animal>().IsValidlOrder(AnimalOrder);
}
Note that this method iterate just once on the list and returns as soon as possible (because the All
method returns on the first item that doesn't match, and the Select
method is executed just when it is needed by the iteration).
public static bool IsValidOrder<T>(this IEnumerable<T> items, IEnumerable<T> order)
{
IEnumerator<T> orderEnumerator = order.GetEnumerator();
orderEnumerator.MoveNext();
return items.All(item => orderEnumerator.ReadUntilGet(item));
}
public static bool ReadUntilGet<T>(this IEnumerator<T> enumerator, T item)
{
return enumerator.Current.Equals(item) ||
(enumerator.MoveNext() && enumerator.ReadUntilGet(item));
}
The ReadUntilGet<T>
method check if the current is equals to the T item, if it is not it moves the enumerator to the next position and calls itself recursively until it finds the T item, then it returns true. If it reaches the end of the enumerator without finding the T item, it returns false.
Since the animals can contain names which string representation is not equal to a enum identifier it's better to use strings to define the order, as @Mat'sMug pointed out.
We can define the order in a list. Notice that numbers indicating the order are not needed because the order of the list is guaranteed to remain the same (the IEnumerable<T>
interface just iterates, it does not change ordering, AFAIK. At this answer it's said otherwise, would you care to explain? I don't have enough reputation to comment):
public static IEnumerable<string> AnimalOrder { get; } = new List<string>
{
"Cat",
"Horse",
"Dog",
"Elephant",
"Great white shark"
};
So, your method would be:
public bool ValidateAnimalOrder(List<string> listOfAnimals)
{
return listOfAnimals.IsValidOrder(AnimalOrder);
}
Note that this method iterate just once on both lists and returns as soon as possible (because the All
method returns on the first item that doesn't match).
Note that this method iterate just once on the list and returns as soon as possible (because the All
method returns on the first item that doesn't match, and the Select
method is executed just when it is needed by the iteration).
Note that this method iterate just once on the list and returns as soon as possible (because the All
method returns on the first item that doesn't match, and the Select
method is executed just when it is needed by the iteration).