Перейти к содержимому

Как заменить foreach на for c

  • автор:

Рефакторинг кода для преобразования цикла for в оператор foreach и наоборот

Область применения:yesVisual Studio Visual Studio для Mac noVisual Studio Code no

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

Преобразование цикла for в оператор foreach

Если у вас есть цикл for в коде, можно использовать этот рефакторинг кода для преобразования цикла в оператор foreach.

Область применения этого рефакторинга:

Рефакторинг с помощью быстрого действия Преобразовать в foreach доступен только для циклов for, которые содержат все три части: инициализатор, условие и итератор.

Для чего это нужно

Причины, из-за которых может потребоваться преобразование цикла for в оператор foreach, включают в себя:

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

Использование

  1. Поместите курсор на ключевое слово for .
  2. Нажмите клавиши CTRL+ или щелкните значок отвертки Screwdriver iconв поле файла кода. Convert to foreach menu
  3. Выберите Преобразовать в foreach. Также можно выбрать Просмотр изменений, чтобы открыть диалоговое окно Просмотр изменений, и нажать Применить.

Преобразование оператора foreach в цикл for

Если у вас есть оператор foreach (C#) или For Each. Next (Visual Basic) в коде, их можно преобразовать в цикл for с помощью этого рефакторинга кода.

Область применения этого рефакторинга:

Для чего это нужно

Причины, из-за которых может потребоваться преобразование оператора foreach в цикл for, включают в себя:

  • Вы хотите использовать локальную переменную внутри цикла не только для доступа к элементу.
  • Вы перебираете элементы многомерного массива и вам требуется больший контроль над элементами массива.

Использование

  1. Поместите курсор на ключевое слово foreach или For Each .
  2. Нажмите клавиши CTRL+ или щелкните значок отвертки Screwdriver iconв поле файла кода. Convert to for menu
  3. Выберите Преобразовать в for. Также можно выбрать Просмотр изменений, чтобы открыть диалоговое окно Просмотр изменений, и нажать Применить.
  4. Так как в данном случае рефакторинг кода порождает новую переменную — счетчик итераций, в правом верхнем углу редактора появится поле Переименовать. Если необходимо выбрать другое имя для переменной, введите его и нажмите клавишу ВВОД или кнопку Применить в поле Переименовать. Если вы не хотите изменять имя, нажмите клавишу ESC или кнопку Применить, чтобы закрыть поле Переименовать.

Код C#, созданный в процессе выполнения рефакторинга, использует явный тип или ключевое слово var для этого типа элементов в коллекции. Тип в созданном коде (явный или неявный) зависит от параметров стиля кода, которые находятся в области. Эти параметры стиля кода настраиваются на уровне компьютера в разделе Параметры>текстового редактора текста» C#>Code Style>General’var> или на уровне решения в файле EditorConfig.> Если вы измените эти параметры в меню Параметры, снова откройте файл кода, чтобы изменения вступили в силу.

См. также

  • Рефакторинг
  • Просмотр изменений

Как цикл foreach поменять на обычный for?

Строго говоря, заменить foreach на доступ по индексу(порядковому номеру) можно не для всех коллекций, например Set не поддерживает такого доступа в принципе. С другой стороны нужно помнить, что некоторые коллекции, например LinkedList при индексном доступе тратят O(n) времени для доступа к n -му элементу коллекции! Итерировать коллекцию по индексу наподобие carPool.get(i); следует только, если коллекция поддерживает доступ по индексу за константное время ( O(1) ). Например классы, реализующие интерфейс RandomAccess предоставляют такой доступ.

Поэтому для задач, где есть необходимость знать индекс текущего элемента и не поддерживающих доступ по индексу или требующих линейного времени доступа к элементу по индексу, следует использовать итератор, а номер индекса считать в отдельной переменной, например вот так:

int i = 0; for (Iterator iter = collection.iterator(); iter.hasNext(); i++)

Отслеживать
ответ дан 13 июл 2016 в 7:00
Mikhailov Valentin Mikhailov Valentin
1,980 12 12 серебряных знаков 21 21 бронзовый знак

Логично, да. В .NET, кстати, есть интерфейс IList , который можно проверить, чтобы узнать, реализует ли коллекция эффективный доступ по индексу. А в Java есть такое?

13 июл 2016 в 7:11
13 июл 2016 в 8:38
Ага, круто, спасибо.
13 июл 2016 в 8:48

@VladD все же прямым аналогом IList является, внезапно, List . RandomAccess — это лишь маркер что доступ по индексу является предпочтительным.

Array.prototype.forEach()

Метод forEach() выполняет указанную функцию один раз для каждого элемента в массиве.

Интерактивный пример

Синтаксис

arr.forEach(function callback(currentValue, index, array) < //your iterator >[, thisArg]);

Параметры

Функция, которая будет вызвана для каждого элемента массива. Она принимает от одного до трёх аргументов:

Текущий обрабатываемый элемент в массиве.

Индекс текущего обрабатываемого элемента в массиве.

Массив, по которому осуществляется проход.

Необязательный параметр. Значение, используемое в качестве this при вызове функции callback .

Возвращаемое значение

Описание

Метод forEach() выполняет функцию callback один раз для каждого элемента, находящегося в массиве в порядке возрастания. Она не будет вызвана для удалённых или пропущенных элементов массива. Однако, она будет вызвана для элементов, которые присутствуют в массиве и имеют значение undefined .

Функция callback будет вызвана с тремя аргументами:

  • значение элемента (value)
  • индекс элемента (index)
  • массив, по которому осуществляется проход (array)

Если в метод forEach() был передан параметр thisArg , при вызове callback он будет использоваться в качестве значения this . В противном случае, в качестве значения this будет использоваться значение undefined . В конечном итоге, значение this , наблюдаемое из функции callback , определяется согласно обычным правилам определения this , видимого из функции .

Диапазон элементов, обрабатываемых методом forEach() , устанавливается до первого вызова функции callback . Элементы, добавленные в массив после начала выполнения метода forEach() , не будут посещены функцией callback . Если существующие элементы массива изменятся, значения, переданные в функцию callback , будут значениями на тот момент времени, когда метод forEach() посетит их; удалённые элементы посещены не будут. Если уже посещённые элементы удаляются во время итерации (например, с помощью shift() ), последующие элементы будут пропущены. ( Смотри пример ниже )

Примечание: Не существует способа остановить или прервать цикл forEach() кроме как выбрасыванием исключения. Если вам необходимо такое поведение, метод forEach() неправильный выбор.

Досрочное прекращение может быть достигнуто с:

  • Простой цикл for
  • Циклы for. of / for. in
  • Array.prototype.every()
  • Array.prototype.some()
  • Array.prototype.find()
  • Array.prototype.findIndex()

Если нужно протестировать элементы массива на условие и нужно вернуть булево значение, вы можете воспользоваться методами every() , some() , find() или findIndex() .

Метод forEach() выполняет функцию callback один раз для каждого элемента массива; в отличие от методов every() и some() , он всегда возвращает значение undefined .

Примеры

Нет операции для неинициализированных значений (разреженные массивы)

const arraySparse = [1, 3, , 7]; let numCallbackRuns = 0; arraySparse.forEach((element) =>  console.log(element); numCallbackRuns++; >); console.log("numCallbackRuns: ", numCallbackRuns); // 1 // 3 // 7 // numCallbackRuns: 3 // комментарий: как вы видите пропущенное значение между 3 и 7 не вызывало функцию callback. 

Конвертируем цикл for в forEach

const items = ["item1", "item2", "item3"]; const copy = []; // до for (let i = 0; i  items.length; i++)  copy.push(items[i]); > // после items.forEach(function (item)  copy.push(item); >); 

Печать содержимого массива

Примечание: Для отображения содержимого массива в консоли вы можете использовать console.table() , который выводит отформатированную версию массива.

Следующий пример иллюстрирует альтернативный подход, использующий forEach() .

Следующий код выводит каждый элемент массива на новой строке журнала:

function logArrayElements(element, index, array)  console.log("a[" + index + "] token operator">+ element); > // Обратите внимание на пропуск по индексу 2, там нет элемента, поэтому он не посещается [2, 5, , 9].forEach(logArrayElements); // логи: // a[0] = 2 // a[1] = 5 // a[3] = 9 

Использование thisArg

Следующий (надуманный) пример обновляет свойства объекта, когда перебирает записи массива:

function Counter()  this.sum = 0; this.count = 0; > Counter.prototype.add = function (array)  array.forEach((entry) =>  this.sum += entry; ++this.count; >, this); // ^---- Note >; const obj = new Counter(); obj.add([2, 5, 9]); obj.count; // 3 obj.sum; // 16 

Поскольку в forEach() передан параметр thisArg ( this ), он затем передаётся в callback при каждом вызове. И callback использует его в качестве собственного значения this .

Примечание: Если при передаче callback функции используется выражение стрелочной функции , параметр thisArg может быть опущен, так как все стрелочные функции лексически привязываются к значению this .

Прерывание цикла

Следующий код использует Array.prototype.every() для логирования содержимого массива и останавливается при превышении значением заданного порогового значения THRESHOLD .

var THRESHOLD = 12; var v = [5, 2, 16, 4, 3, 18, 20]; var res; res = v.every(function (element, index, array)  console.log("element:", element); if (element >= THRESHOLD)  return false; > return true; >); console.log("res:", res); // логи: // element: 5 // element: 2 // element: 16 // res: false res = v.some(function (element, index, array)  console.log("element:", element); if (element >= THRESHOLD)  return true; > return false; >); console.log("res:", res); // логи: // element: 5 // element: 2 // element: 16 // res: true 

Функция копирования объекта

Следующий код создаёт копию переданного объекта. Существует несколько способов создания копии объекта, и это один из них. Он позволяет понять, каким образом работает Array.prototype.forEach() , используя функции мета-свойств Object.* из ECMAScript 5.

function copy(o)  var copy = Object.create(Object.getPrototypeOf(o)); var propNames = Object.getOwnPropertyNames(o); propNames.forEach(function (name)  var desc = Object.getOwnPropertyDescriptor(o, name); Object.defineProperty(copy, name, desc); >); return copy; > var o1 =  a: 1, b: 2 >; var o2 = copy(o1); // теперь o2 выглядит также, как и o1 

Модификация массива во время итерации

В следующем примере в лог выводится «one» , «two» , «four» .

При достижении записи, содержащей значение ‘two’ , первая запись всего массива удаляется, в результате чего все оставшиеся записи перемещаются на одну позицию вверх. Поскольку элемент ‘four’ теперь находится на более ранней позиции в массиве, ‘three’ будет пропущен.

forEach() не делает копию массива перед итерацией.

let words = ["one", "two", "three", "four"]; words.forEach((word) =>  console.log(word); if (word === "two")  words.shift(); > >); // one // two // four 

Выравнивание (уплощение) массива

Следующий пример приведён только для целей обучения. Если вы хотите выравнять массив с помощью встроенных методов, вы можете использовать Array.prototype.flat()

function flatten(arr)  const result = []; arr.forEach((i) =>  if (Array.isArray(i))  result.push(. flatten(i)); > else  result.push(i); > >); return result; > // Usage const nested = [1, 2, 3, [4, 5, [6, 7], 8, 9]]; flatten(nested); // [1, 2, 3, 4, 5, 6, 7, 8, 9] 

Полифил

Метод forEach() был добавлен к стандарту ECMA-262 в 5-м издании; поэтому он может отсутствовать в других реализациях стандарта. Вы можете работать с ним, добавив следующий код в начало ваших скриптов, он позволяет использовать forEach() в реализациях, которые не поддерживают этот метод. Этот алгоритм является точно тем, что описан в ECMA-262 5-го издания; он предполагает, что Object и TypeError имеют свои первоначальные значения и что callback.call вычисляется в оригинальное значение Function.prototype.call() .

// Шаги алгоритма ECMA-262, 5-е издание, 15.4.4.18 // Ссылка (en): http://es5.github.io/#x15.4.4.18 // Ссылка (ru): http://es5.javascript.ru/x15.4.html#x15.4.4.18 if (!Array.prototype.forEach)  Array.prototype.forEach = function (callback, thisArg)  var T, k; if (this == null)  throw new TypeError(" this is null or not defined"); > // 1. Положим O равным результату вызова ToObject passing the |this| value as the argument. var O = Object(this); // 2. Положим lenValue равным результату вызова внутреннего метода Get объекта O с аргументом "length". // 3. Положим len равным ToUint32(lenValue). var len = O.length >>> 0; // 4. Если IsCallable(callback) равен false, выкинем исключение TypeError. // Смотрите: http://es5.github.com/#x9.11 if (typeof callback !== "function")  throw new TypeError(callback + " is not a function"); > // 5. Если thisArg присутствует, положим T равным thisArg; иначе положим T равным undefined. if (arguments.length > 1)  T = thisArg; > // 6. Положим k равным 0 k = 0; // 7. Пока k < len, будем повторятьwhile (k  len)  var kValue; // a. Положим Pk равным ToString(k). // Это неявное преобразование для левостороннего операнда в операторе in // b. Положим kPresent равным результату вызова внутреннего метода HasProperty объекта O с аргументом Pk. // Этот шаг может быть объединён с шагом c // c. Если kPresent равен true, то if (k in O)  // i. Положим kValue равным результату вызова внутреннего метода Get объекта O с аргументом Pk. kValue = O[k]; // ii. Вызовем внутренний метод Call функции callback с объектом T в качестве значения this и // списком аргументов, содержащим kValue, k и O. callback.call(T, kValue, k, O); > // d. Увеличим k на 1. k++; > // 8. Вернём undefined. >; > 

Спецификации

Specification
ECMAScript Language Specification
# sec-array.prototype.foreach

Совместимость с браузерами

BCD tables only load in the browser

Смотрите также

  • Array.prototype.find()
  • Array.prototype.findIndex()
  • Array.prototype.map()
  • Array.prototype.every()
  • Array.prototype.some()
  • Map.prototype.forEach() (en-US)
  • Set.prototype.forEach()

Как заменить foreach на for c

В C# массив объявляется следующим образом:

Инициализация массива в C#

Примечание

Индексация массивов в C# начинается с 0. То есть первый элемент массива имеет индекс 0. Если размер массива равен 5, то индекс последнего элемента будет равен 4.

Доступ к элементам массива

Для получения доступа к элементам массива используется индекс массива.

Двумерный массив C#

Строки < 1, 2, 3 >и < 4, 5, 6 >– это элементы 2D-массива.

Объявление двумерного массива

Вот как объявляется двумерный массив в C#:

Элементы двумерного массива в C# Работа цикла C# foreach

Ключевое слово in используется вместе с циклом foreach для перебора элементов iterable-item . in выбирает элемент из iterable-item на каждой итерации и сохраняет в переменной element .

На первой итерации первый элемент iterable-item сохраняется в element . На второй итерации второй элемент сохраняется в element и т. д.

Число выполнений цикла foreach равно количеству элементов в массиве или коллекции.

Вот пример перебора массива с помощью цикла for :

Вывод массива используя цикл for

using System; namespace Loop < class ForLoop < public static void Main(string[] args) < char[] myArray = ; for(int i = 0; i < myArray.Length; i++) < Console.WriteLine(myArray[i]); >> > > 

Эта же задача решается с помощью цикла foreach .

Вывод массива используя цикл foreach

using System; namespace Loop < class ForEachLoop < public static void Main(string[] args) < char[] myArray = ; foreach(char ch in myArray) < Console.WriteLine(ch); >> > > 

После запуска обеих программ вывод будет таким:

В приведенной выше программе цикл foreach перебирает массив myArray . На первой итерации первый элемент, т. е. myArray[0] выбирается и сохраняется в ch .

Аналогично, на последней итерации выбирается последний элемент, т. е. myArray[4] . Внутри тела цикла выводится значение ch .

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

Следующая программа подсчитывает количество кандидатов мужского и женского пола.

Обход массива полов с использованием цикла foreach

using System; namespace Loop < class ForEachLoop < public static void Main(string[] args) < char[] gender = ; int male = 0, female = 0; foreach (char g in gender) < if (g == 'm') male++; else if (g =='f') female++; >Console.WriteLine("Number of male = ", male); Console.WriteLine("Number of female = ", female); > > > 

Number of male = 6
Number of female = 4

Следующая программа подсчитывает сумму элементов в List .

Цикл foreach с List (список или коллекция)

using System; using System.Collections.Generic; namespace Loop < class ForEachLoop < public static void Main(string[] args) < var numbers = new List() < 5, -8, 3, 14, 9, 17, 0, 4 >; int sum = 0; foreach (int number in numbers) < sum += number; >Console.WriteLine("Sum = ", sum); Console.ReadLine(); > > > 

В этой программе цикл foreach используется для обхода коллекции. Обход коллекции похож на обход массива.

Первый элемент коллекции выбирается на первой итерации, второй элемент на второй и т. д. до последнего элемента.

Из этой статьи мы узнали

  • Как работать с одномерными, многомерными и ступенчатыми массивами.
  • Как работать с циклом foreach .
  • О пространстве имен System.Linq и несколько примеров работы с ним.

Материалы по теме

  • ��‍��️ Самоучитель по C# для начинающих. Часть 1: установите среду разработки и освойте основы языка за 30 минут
  • ❓ Как использовать обобщения в C# – краткая инструкция для новичков
  • �� 8 шагов от новичка до профессионала: дорожная карта разработчика на C#

Источники

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *