Вот функция, которую вы можете использовать для дедуплирования строки, как вы описали. Обратите внимание, что это не будет сортировать дедуплированную строку, поэтому, если ваш был чем-то вроде «4,2,5,1,3,2,2», результат был бы «4,2,5,1,3». Вы не указали, что вам нужно было его отсортировать, поэтому я не включил эту функциональность. Обратите внимание, что функция использует ,
в качестве разделителя по умолчанию, если не указана, но вы можете указать разделитель, если вы выберете.
Function DeDupeString(ByVal sInput As String, Optional ByVal sDelimiter As String = ",") As String
Dim varSection As Variant
Dim sTemp As String
For Each varSection In Split(sInput, sDelimiter)
If InStr(1, sDelimiter & sTemp & sDelimiter, sDelimiter & varSection & sDelimiter, vbTextCompare) = 0 Then
sTemp = sTemp & sDelimiter & varSection
End If
Next varSection
DeDupeString = Mid(sTemp, Len(sDelimiter) + 1)
End Function
Вот несколько примеров того, как вы это назвали:
Sub tgr()
MsgBox DeDupeString("1,2,3,4,5,2,2") '--> "1,2,3,4,5"
Dim myString As String
myString = DeDupeString("4-2-5-1-3-2-2", "-")
MsgBox myString '--> "4-2-5-1-3"
End Sub
Во-первых, обратите внимание, что одна большая разница в Вашем примере (между foreach
и GetEnumerator
) - то, что foreach
гарантии для вызова Dispose()
на итераторе, если итератор IDisposable
. Это важно для многих итераторов (который мог бы использовать внешний канал данных, например).
На самом деле, существуют случаи, где foreach
не так полезно, как мы хотели бы.
Первый, существует "первый объект" случай, обсудил здесь (foreach / обнаружение первого повторения) .
, Но больше; при попытке писать пропавшим без вести Zip
метод для сшивания двух счетных последовательностей вместе (или SequenceEqual
метод), Вы находите, что можно' использовать foreach
на обеих последовательностях, так как это выполнило бы перекрестное объединение. Необходимо использовать итератор непосредственно для одного из них:
static IEnumerable<T> Zip<T>(this IEnumerable<T> left,
IEnumerable<T> right)
{
using (var iter = right.GetEnumerator())
{
// consume everything in the first sequence
foreach (var item in left)
{
yield return item;
// and add an item from the second sequnce each time (if we can)
if (iter.MoveNext())
{
yield return iter.Current;
}
}
// any remaining items in the second sequence
while (iter.MoveNext())
{
yield return iter.Current;
}
}
}
static bool SequenceEqual<T>(this IEnumerable<T> left,
IEnumerable<T> right)
{
var comparer = EqualityComparer<T>.Default;
using (var iter = right.GetEnumerator())
{
foreach (var item in left)
{
if (!iter.MoveNext()) return false; // first is longer
if (!comparer.Equals(item, iter.Current))
return false; // item different
}
if (iter.MoveNext()) return false; // second is longer
}
return true; // same length, all equal
}
Согласно спецификация языка C#:
А foreach оператор формы
foreach (V v in x) embedded-statement
тогда расширен до:
{
E e = ((C)(x)).GetEnumerator();
try {
V v;
while (e.MoveNext()) {
v = (V)(T)e.Current;
embedded-statement
}
}
finally {
... // Dispose e
}
}
сущность Ваших двух примеров является тем же, но существуют некоторые важные различия, прежде всего try
/ finally
.
В C#, foreach
делает точно то же самое как эти IEnumerator
код, который Вы отправили выше. Эти foreach
конструкция обеспечивается для облегчения для программиста. Я полагаю, что IL, сгенерированный в обоих случаях, является тем же/подобным.
Я использовал его иногда, когда первое повторение делает что-то другое от других.
, Например, если Вы хотите распечатать участников, чтобы подключиться с консоли и разделить результаты с методической точностью, можно записать.
using (IEnumerator<MyClass> classesEnum = myClasses.GetEnumerator()) {
if (classEnum.MoveNext())
Console.WriteLine(classesEnum.Current);
while (classesEnum.MoveNext()) {
Console.WriteLine("-----------------");
Console.WriteLine(classesEnum.Current);
}
}
Тогда результат
myClass 1
-----------------
myClass 2
-----------------
myClass 3
, И другая ситуация состоит в том, когда я выполняю итерации 2 перечислителей вместе.
using (IEnumerator<MyClass> classesEnum = myClasses.GetEnumerator()) {
using (IEnumerator<MyClass> classesEnum2 = myClasses2.GetEnumerator()) {
while (classesEnum.MoveNext() && classEnum2.MoveNext())
Console.WriteLine("{0}, {1}", classesEnum.Current, classesEnum2.Current);
}
}
результат
myClass 1, myClass A
myClass 2, myClass B
myClass 3, myClass C
Используя перечислитель позволяет Вам делать более гибкий на Вашем повторении. Но в большей части случая, можно использовать foreach