Я всегда борюсь с чем-то как следующий пример Java:
String breads[] = {"Brown", "White", "Sandwich"};
int count[] = new int[breads.length];
for (int i = 0; i < ****; i++)
{
// Prompt the number of breads
}
****
: какой array.length я должен выбрать?
Я могу выбрать между breads.length
и count.length
Я знаю, что это был бы тот же результат, но я не знаю, какой я shoud выбирают.
Существует много других примеров, где я получаю ту же проблему.
Я уверен, что Вы встретились с этой проблемой также в прошлом.
Что необходимо выбрать? Есть ли генеральные соглашения?
Спасибо
Думаю, я понял ваш вопрос.
Ответ: не используйте массивы.
В этом случае используйте карту:
Map<String, Integer> breadCount = new TreeMap<String, Integer>();
breadCount.put("Brown", 0);
breadCount.put("White", 0);
breadCount.put("Sandwich", 0);
Тогда есть только одна «длина», которая равна breadCount.size ()
Пример в Java
В этом сценарии я бы выбрал хлебов
, потому что именно так вы объясняете код.
Логично, что вы перебираете каждый вид хлеба, а не количество хлеба (хотя это одно и то же).
Представьте, что вы объясняете свой код кому-то другому, и используете все, что имеет смысл с этой точки зрения. Иногда оба имеют смысл, и в этом случае вам просто нужно выбирать произвольно.
Это зависит от того, что вы делаете, но в конечном итоге это редко будет важным решением (поскольку значение то же самое) . Возможно, беспокоятся о «более серьезных» проблемах. Для интереса, в .NET JIT (, а не компилятор) может обнаружить этот шаблон и исключить проверки выхода за границы, но только если это очевидно, например:
for(int i = 0 ; i < arr.Length ; i++) {
Console.WriteLine(arr[i]); // no bounds check if the JIT can prove it will
// never fail
}
Вы используете for(int i=0; i
array[i]
, а не что-то другое. В вашем случае вы хотите выполнять итерации по именам, которые вы определили. Массив count, однако, заполнен нулями, и вопрос в том, почему вы хотите итерироваться по ним. Так что если вы напишете
String breads[] = {"Brown", "White", "Sandwich"};
int count[] = new int[breads.length];
for (int i = 0; i < breads.length; i++) {
}
вы ясно увидите, что цикл предназначен для итерации по именам. И вы работаете с этими именами (например, показываете их). Но если вы напишете
String breads[] = {"Brown", "White", "Sandwich"};
int count[] = new int[breads.length];
for (int i = 0; i < count.length; i++) {
}
Возникает вопрос почему вы хотите перебирать значения count? Они все равны 0.
На самом деле поток данных выглядит примерно так count_value = f(bread_value)
, названия хлеба - независимая переменная. Вы можете написать (на Java)
String breads[] = {"Brown", "White", "Sandwich"};
int count[] = new int[breads.length];
for (String bread: breads) {
}
и явно видите, что вас волнуют имена хлебов и вы хотите что-то с ними сделать. То, что вы хотите установить counts - это просто побочный эффект цикла, но он не контролирует время итераций.
Я бы попытался вообще не использовать разные массивы. Чаще всего, если у вас есть два массива, которые всегда имеют одинаковый размер, вы фактически имитируете составной тип или отношение.
// C++: inventory map:
std::map< std::string, int > bread_inventory;
bread_inventory["White"] = 0;
bread_inventory["Brown"] = 0;
bread_inventory["Sandwich"] = 0;
// C++: complex type:
struct bread_type
{
bread_type( std::string const & name, int calories )
: name(name), calories(calories) {}
std::string name;
int calories;
};
std::vector<bread_type> v;
v.push_back( bread_type("White", 100) );
v.push_back( bread_type("Brown", 90) );
Используя конкретные типы или контейнеры (по сравнению с несвязанными элементами в разных контейнерах), вы бесплатно получаете согласованность (нужно меньше заботиться о том, чтобы убедиться, что оба контейнера обновляются одинаково), а некоторые операции становятся намного проще (упорядочивание вектор по калориям можно тривиально реализовать с помощью функции упорядочения, тогда как если вы сохраните два отдельных вектора для имен и связанных значений, вам придется бороться за свой путь, чтобы гарантировать, что одни и те же операции выполняются на обоих контейнерах.
код также легче отслеживать и поддерживать, поскольку типы сообщают программисту, чего хочет писатель. Часть знаний о предметной области, которые вы имеете при написании класса, теряется в вашей реализации. Ваша реализация имеет дело с массивом типов хлеба и один массив счетчиков, но код не говорит вам, что они на самом деле являются одним объектом.
Использование breads.length
является более точным , поскольку count
размер зависит от хлеба
длины, но, кроме этого, разные результаты будут быть таким же .. и это должно быть правдой, когда вы действуете способом, подобным тому, который вы написали.
Если вы действительно не хотите, чтобы вас раздражали эти метафизические вопросы, вы можете использовать простой класс:
class Bread
{
String name;
int count
}
или вы можете использовать многомерный массив, или также хэш-карту:
HashMap<String, Integer> counts
, чтобы вы могли повторять реальную коллекцию при сборе значений с карты:
for (String b : breads)
System.out.println(b + " count: "+counts.get(b));
В такой ситуации я объявляю локальная переменная. Примерно так:
int n = breads.length;
int[] count = new int[n];
for (int i = 0; i < n; i ++) {
// ...
}
Концептуально это означает, что я делаю «счетчик цикла» самостоятельным значением. Побочный эффект - ваша проблема решена.
Я бы сказал, выберите «основной» массив и везде используйте его длину. Таким образом ваш код будет более понятным и легким для чтения. В остальном, я думаю, это не имеет особого значения, потому что count.length будет таким же, и вы можете смешивать эти два, как хотите.
Эта проблема выглядит скорее академичной - но в вашем случае я бы предпочел массив, который вы намереваетесь изменить (подсчитать), поскольку, когда в некотором (скорее академическом) случае длина хлеба и количество должны различаться, Всегда лучше не сталкиваться с проблемами, связанными с границами массива ...
Тем не менее, может быть другое решение: иметь только один массив, содержащий структуры с именем («хлебцы» можно также назвать «имя хлеба») и подсчитывать. ..
Использовать списки, наборы и карты и петли foreach.
Если вам действительно нужно использовать массивы и нельзя использовать циклы foreach, это не имеет значения.