Как вы получаете индекс текущей итерации цикла foreach?

Как говорили другие, минимальные / максимальные значения, которые может хранить столбец, и сколько памяти он занимает в байтах, определяется только типом, а не длиной.

Многие из этих ответов говорят о том, что часть (11) влияет только на ширину отображения, которая не совсем верна, но в основном.

Определение int(2) без Указанный zerofill будет:

  • все еще принимает значение 100
  • , все еще отображая значение 100 при выходе (не 0 или 00)
  • ширина экрана будет шириной наибольшего значения, выводимого из запроса выбора.

Единственное, что будет делать (2), - это также указать нулевое значение :

  • будет показано значение 1 01.
  • При отображении значений столбец всегда будет иметь ширину максимально возможного значения, которое может принимать столбец, который составляет 10 цифр для целого числа, вместо ширины miniumum, необходимой для отображения наибольшего значения, которое требуется столбцу показать в этом конкретном запросе выбора, который может быть намного меньше.
  • Столбец все еще может принимать и показывать значение, превышающее длину, но эти значения не будут иметь префикс с 0.

Лучший способ увидеть все нюансы:

CREATE TABLE `mytable` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `int1` int(10) NOT NULL,
    `int2` int(3) NOT NULL,
    `zerofill1` int(10) ZEROFILL NOT NULL,
    `zerofill2` int(3) ZEROFILL NOT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `mytable` 
(`int1`, `int2`, `zerofill1`, `zerofill2`) 
VALUES
(10000, 10000, 10000, 10000),
(100, 100, 100, 100);

select * from mytable;

, который будет выводиться:

+----+-------+-------+------------+-----------+
| id | int1  | int2  | zerofill1  | zerofill2 |
+----+-------+-------+------------+-----------+
|  1 | 10000 | 10000 | 0000010000 |     10000 |
|  2 |   100 |   100 | 0000000100 |       100 |
+----+-------+-------+------------+-----------+

Обратите внимание, что столбец int1 имеет гораздо меньшая ширина дисплея, чем zerofill2, даже если длина больше.

Этот ответ протестирован против MySQL 5.7.12 для Linux и может отличаться или не изменяться для других реализаций.

808
задан AustinWBryan 23 March 2019 в 08:51
поделиться

12 ответов

Эти foreach для итерации по наборам, которые реализуют IEnumerable . Это делает это путем вызова GetEnumerator на наборе, который возвратится Enumerator .

Этот Перечислитель имеет метод и свойство:

  • MoveNext ()
  • Текущий

Current возвраты объект, что Перечислитель в настоящее время включен, MoveNext обновления Current к следующему объекту.

понятие индекса является внешним к понятию перечисления и не может быть сделано.

Из-за этого, большинство наборов в состоянии быть пересеченным с помощью индексатора и для конструкции цикла.

я значительно предпочитаю использовать для цикла в этой ситуации по сравнению с отслеживанием индекса с локальной переменной.

501
ответ дан Moriya 23 March 2019 в 08:51
поделиться

Я не полагаю, что существует способ получить значение текущего повторения цикла foreach. Подсчет себя, кажется, лучший способ.

май я спрашиваю, почему Вы хотели бы знать?

кажется, что Вы были бы самый вероятный сделать одну из трех вещей:

1) Получение объекта от набора, но в этом случае у Вас уже есть он.

2) подсчет объектов для более позднего сообщения, обрабатывающего... наборы, имеет свойство Count, которое Вы могли использовать.

3) Установка свойства на основанном на объектах на его порядке в цикле..., хотя Вы могли легко устанавливать это, когда Вы добавили объект к набору.

2
ответ дан bryansh 23 March 2019 в 08:51
поделиться

Если Ваш набор не может возвратить индекс объекта с помощью некоторого метода, единственный путь состоит в том, чтобы использовать счетчик как в Вашем примере.

Однако при работе с индексами, единственный разумный ответ на проблему должен использовать для цикла. Что-либо еще представляет сложность кода, не говоря уже о сложности времени и пространства.

2
ответ дан Joseph Daigle 23 March 2019 в 08:51
поделиться

Мог сделать что-то вроде этого:

public static class ForEachExtensions
{
    public static void ForEachWithIndex<T>(this IEnumerable<T> enumerable, Action<T, int> handler)
    {
        int idx = 0;
        foreach (T item in enumerable)
            handler(item, idx++);
    }
}

public class Example
{
    public static void Main()
    {
        string[] values = new[] { "foo", "bar", "baz" };

        values.ForEachWithIndex((item, idx) => Console.WriteLine("{0}: {1}", idx, item));
    }
}
107
ответ дан Brad Wilson 23 March 2019 в 08:51
поделиться

Это только собирается работать на Список и не любой IEnumerable, но в LINQ существует это:

IList<Object> collection = new List<Object> { 
    new Object(), 
    new Object(), 
    new Object(), 
    };

foreach (Object o in collection)
{
    Console.WriteLine(collection.IndexOf(o));
}

Console.ReadLine();

@Jonathan я не сказал, что это был большой ответ, я просто сказал, что это просто показывало, что было возможно сделать то, что он спросил:)

@Graphain я не ожидал бы, что он будет быстр - я не совсем уверен, как это работает, это могло повторить через весь список каждый раз для нахождения соответствующего объекта, который будет helluvalot, выдерживает сравнение.

Однако Список мог бы сохранить индекс каждого объекта наряду с количеством.

у Jonathan, кажется, есть лучшая идея, если он уточнил бы?

было бы лучше просто провести подсчет того, где Вы готовы в foreach хотя, более просты, и более адаптируемы.

9
ответ дан crucible 23 March 2019 в 08:51
поделиться

Литеральный Ответ - предупреждение, производительность не может быть столь же хорошей как просто использование int для отслеживания индекса. По крайней мере, это лучше, чем использование IndexOf.

просто необходимо использовать перегрузку индексации Выбора для обертывания каждого объекта в набор с анонимным объектом, который знает индекс. Это может быть сделано против чего-либо, что реализует IEnumerable.

System.Collections.IEnumerable collection = Enumerable.Range(100, 10);

foreach (var o in collection.OfType<object>().Select((x, i) => new {x, i}))
{
    Console.WriteLine("{0} {1}", o.i, o.x);
}
58
ответ дан SteveC 23 March 2019 в 08:51
поделиться

Я не согласен с комментариями о том, что в большинстве случаев лучше использовать цикл для .

foreach - полезная конструкция, и ее нельзя заменить циклом for ни при каких обстоятельствах.

Например, если у вас есть DataReader и вы просматриваете все записи с помощью foreach , он автоматически вызывает метод Dispose и закрывает считыватель (который может затем закройте соединение автоматически). Таким образом, это безопаснее, поскольку предотвращает утечку соединения, даже если вы забыли закрыть считыватель.

(Конечно, это хорошая практика - всегда закрывать читатели, но компилятор не поймает это, если вы этого не сделаете - вы не можете гарантировать, что закрыли всех читателей, но вы можете повысить вероятность того, что выиграете »

89
ответ дан 22 November 2019 в 21:09
поделиться

Вот решение, которое я только что придумал для этой проблемы

Original code:

int index=0;
foreach (var item in enumerable)
{
    blah(item, index); // some code that depends on the index
    index++;
}

Updated code

enumerable.ForEach((item, index) => blah(item, index));

Extension Method:

    public static IEnumerable<T> ForEach<T>(this IEnumerable<T> enumerable, Action<T, int> action)
    {
        var unit = new Unit(); // unit is a new type from the reactive framework (http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx) to represent a void, since in C# you can't return a void
        enumerable.Select((item, i) => 
            {
                action(item, i);
                return unit;
            }).ToList();

        return pSource;
    }
18
ответ дан 22 November 2019 в 21:09
поделиться
int index;
foreach (Object o in collection)
{
    index = collection.indexOf(o);
}

Это будет работать для коллекций, поддерживающих IList.

8
ответ дан 22 November 2019 в 21:09
поделиться

Вы можете заключить исходный перечислитель в другой, который действительно содержит информацию об индексе.

foreach (var item in ForEachHelper.WithIndex(collection))
{
    Console.Write("Index=" + item.Index);
    Console.Write(";Value= " + item.Value);
    Console.Write(";IsLast=" + item.IsLast);
    Console.WriteLine();
}

Вот код для класса ForEachHelper .

public static class ForEachHelper
{
    public sealed class Item<T>
    {
        public int Index { get; set; }
        public T Value { get; set; }
        public bool IsLast { get; set; }
    }

    public static IEnumerable<Item<T>> WithIndex<T>(IEnumerable<T> enumerable)
    {
        Item<T> item = null;
        foreach (T value in enumerable)
        {
            Item<T> next = new Item<T>();
            next.Index = 0;
            next.Value = value;
            next.IsLast = false;
            if (item != null)
            {
                next.Index = item.Index + 1;
                yield return item;
            }
            item = next;
        }
        if (item != null)
        {
            item.IsLast = true;
            yield return item;
        }            
    }
}
25
ответ дан 22 November 2019 в 21:09
поделиться

Лучше использовать ключевое слово continue безопасную конструкцию, подобную этой

int i=-1;
foreach (Object o in collection)
{
    ++i;
    //...
    continue; //<--- safe to call, index will be increased
    //...
}
4
ответ дан 22 November 2019 в 21:09
поделиться

Вот как я это делаю, что приятно своей простотой / краткостью, но если вы много делаете в теле цикла obj.Value , это скоро состарится.

foreach(var obj in collection.Select((item, index) => new { Index = index, Value = item }) {
    string foo = string.Format("Something[{0}] = {1}", obj.Index, obj.Value);
    ...
}
8
ответ дан 22 November 2019 в 21:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: