Идентификация последнего цикла при использовании для каждого

 CGAffineTransform currentCTM = CGContextGetCTM(context);     if
 (currentCTM.a == 1.0 && baseImage)  {
     //Calculate ideal scale
     CGFloat scaleForWidth = baseImage.size.width/self.bounds.size.width;
     CGFloat scaleForHeight = baseImage.size.height/self.bounds.size.height; 
     CGFloat imageScaleFactor = MAX(scaleForWidth, scaleForHeight);
     CGSize imageSize = CGSizeMake(baseImage.size.width/imageScaleFactor,
 baseImage.size.height/imageScaleFactor);
     CGRect imageRect = CGRectMake((self.bounds.size.width-imageSize.width)/2,
 (self.bounds.size.height-imageSize.height)/2, imageSize.width,
 imageSize.height);
     CGContextDrawImage(context, imageRect, [baseImage CGImage]); }  else  {
     @synchronized(issue)  { 
         CGPDFPageRef pdfPage = CGPDFDocumentGetPage(issue.pdfDoc, pageIndex+1);
         pdfToPageTransform = CGPDFPageGetDrawingTransform(pdfPage, kCGPDFMediaBox, layer.bounds, 0, true);
         CGContextConcatCTM(context, pdfToPageTransform);    
         CGContextDrawPDFPage(context, pdfPage);
     } }
48
задан Syed Tayyab Ali 1 July 2009 в 03:00
поделиться

21 ответ

Попытаться пойти на уступки, но нарушить проект в небольших проектах / API / модулях / пакетах / сборках (называйте их как хотите) должен стать следующим логическим шагом здесь.

  • Начал с малого, несколько файлов, небольшой редактор, сборки командной строки, все было хорошо ...
  • Увеличился, версии стали сложнее, перенесены на SVN и IDE ... БОЛЬШОЕ повышение производительности
  • Затем проект стал еще больше, и снова возникает чувство подавленности ...

Человеческий мозг может только обрабатывать так много вещей одновременно, наша рабочая память настолько много, что может обработать. Скрытие мелких деталей за более высоким уровнем абстракции позволит вам забыть об этих файлах, пока под капотом не что-то не так. Если это когда-нибудь произойдет, вам нужно только открыть именно этот капюшон, чтобы исправить это там. Используйте другой уровень абстракции, и ваши проекты внезапно станут намного меньше, где только несколько единиц будут иметь смысл, а остальное - просто заставить их работать. ООП очень хорошо скрывает детали реализации, открывая доступ к функционалистам более высокого уровня. При этом есть и другие парадигмы, помимо ООП, из которых вы можете выбирать.

Итак, мой вам совет на этом этапе

  • Разбейте ваши проекты на более мелкие части, каждый с интерфейсом, который даст вам единую точку доступа к остальные.
  • Используйте модульное тестирование и другие методы тестирования с хорошей структурой тестирования, чтобы тестировать каждый блок по отдельности. Это позволит вам протестировать интерфейс и посмотреть, полезен ли он.
  • Никогда не обращайтесь к тому, что скрывается за интерфейсом, если вы чувствуете необходимость, измените интерфейс, тесты и затем используйте интерфейс. Это самая важная часть, игнорирование этого вернет вас к проблеме, которая у вас есть сейчас (слишком сильная связь), поэтому уменьшите как можно больше точек взаимодействия между чанками, а следовательно, и интерфейсы.

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

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

полезные лакомые кусочки

-121--3758964-

Как насчет получения ссылки сначала к последнему элементу , а затем использовать его для сравнения внутри цикла foreach? Я не говорю, что вам следует это делать, поскольку я сам использовал бы цикл на основе индекса, как упомянул Клауземейер . К сожалению, я не знаю Ruby, поэтому следующий пример написан на C #! Надеюсь, вы не возражаете: -)

string lastItem = list[list.Count - 1];
foreach (string item in list) {
    if (item != lastItem)
        Console.WriteLine("Looping: " + item);
    else    Console.Writeline("Lastone: " + item);
}

Я изменил следующий код для сравнения по ссылке, а не по значению (можно использовать только ссылочные типы, а не типы значений). следующий код должен поддерживать несколько объектов, содержащих одну и ту же строку (но не один и тот же строковый объект), поскольку в примере MattChurcy не указано, что строки должны быть разными, и я использовал метод LINQ Last вместо вычисления индекса.

string lastItem = list.Last();
foreach (string item in list) {
    if (!object.ReferenceEquals(item, lastItem))
        Console.WriteLine("Looping: " + item);
    else        Console.WriteLine("Lastone: " + item);
}

Ограничения приведенного выше кода. (1) Он может работать только для строк или ссылочных типов, но не для типов значений. (2) Один и тот же объект может появиться в списке только один раз. У вас могут быть разные объекты, содержащие одно и то же содержимое. Литеральные строки нельзя использовать повторно, поскольку C # не создает уникальный объект для строк с одинаковым содержанием.

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

23
ответ дан 7 November 2019 в 12:04
поделиться

Как насчет этого? только что выучил немного Руби. hehehe

list.collect {|x|(x!=list.last ? "Looping:"+x:"Lastone:"+x) }.each{|i|puts i}      
0
ответ дан 7 November 2019 в 12:04
поделиться

о чем мы здесь думаем?

public static void main(String[] args) {
    // TODO Auto-generated method stub
    String str = readIndex();
    String comp[] = str.split("}");

    StringBuffer sb = new StringBuffer();
    for (String s : comp) {
        sb.append(s);
        sb.append("}\n");
    }
    System.out.println (sb.toString());
}

Что касается нотации моделирования, преобладает влияние нотации OMT (например, использование прямоугольников для классов и объектов). Хотя «облачная» нотация Буча была исключена, возможность Буча указывать детали проекта нижнего уровня была принята. Нотация вариантов использования из Objectory и нотация компонентов из Booch были интегрированы с остальной нотацией, но семантическая интеграция была относительно слабой в UML 1.1 и не была исправлена ​​до основной версии UML 2.0.

-5
ответ дан 7 November 2019 в 12:04
поделиться

Подобно ответу Кгианнакакиса:

list.first(list.size - 1).each { |i| puts "Looping: " + i }
puts "Last one: " + list.last
0
ответ дан 7 November 2019 в 12:04
поделиться

По крайней мере, в C # это невозможно без обычного цикла for.

Перечислитель в collection решает, существует ли следующий элемент (метод MoveNext), цикл не знает об этом.

1
ответ дан 7 November 2019 в 12:04
поделиться

Думаю, я предпочитаю решение kgiannakakis , однако вы всегда можете сделать что-то вроде этого:

list = ['A','B','C']
list.each { |i|
   if (i != list.last)
      puts "Looping:#{i}"
   else
      puts "Last one:#{i}"
   end
}
1
ответ дан 7 November 2019 в 12:04
поделиться

То, что вы пытаетесь сделать, кажется слишком продвинутым для цикла foreach. Однако вы можете использовать Iterator явно. Например, на Java я бы написал следующее:

Collection<String> ss = Arrays.asList("A","B","C");
Iterator<String> it = ss.iterator();
while (it.hasNext()) {
    String s = it.next();
    if(it.hasNext())
        System.out.println("Looping: " + s);
    else 
        System.out.println("Last one: " + s);
}
2
ответ дан 7 November 2019 в 12:04
поделиться

Конструкция foreach (определенно в Java, возможно, также и в других языках) предназначена для представления самого общего вида итерации if, которая включает итерацию по коллекциям, не имеющим значимого порядка итерации. Например, в наборе на основе хэша нет упорядочивания, и поэтому нет «последнего элемента». Последняя итерация может давать разные элементы при каждой итерации.

В основном: нет, конструкция foreach не предназначена для использования таким образом.

37
ответ дан 7 November 2019 в 12:04
поделиться

If you're using a collection that exposes a Count property - an assumption made by many of the other answers, so I'll make it too - then you can do something like this using C# and LINQ:

foreach (var item in list.Select((x, i) => new { Val = x, Pos = i }))
{
    Console.Write(item.Pos == (list.Count - 1) ? "Last one: " : "Looping: ");
    Console.WriteLine(item.Val);
}

If we additionally assume that the items in the collection can be accessed directly by index - the currently accepted answer assumes this - then a plain for loop will be more elegant/readable than a foreach:

for (int i = 0; i < list.Count; i++)
{
    Console.Write(i == (list.Count - 1) ? "Last one: " : "Looping: ");
    Console.WriteLine(list[i]);
}

If the collection doesn't expose a Count property and can't be accessed by index then there isn't really any elegant way to do this, at least not in C#. A bug-fixed variation of Thomas Levesque's answer is probably as close as you'll get.


Here's the bug-fixed version of Thomas's answer:

string previous = null;
bool isFirst = true;
foreach (var item in list)
{
    if (!isFirst)
    {
        Console.WriteLine("Looping: " + previous);
    }
    previous = item;
    isFirst = false;
}
if (!isFirst)
{
    Console.WriteLine("Last one: " + previous);
}

And here's how I would do it in C# if the collection doesn't expose a Count property and the items aren't directly accessible by index. (Notice that there's no foreach and the code isn't particularly succinct, but it will give decent performance over pretty much any enumerable collection.)

// i'm assuming the non-generic IEnumerable in this code
// wrap the enumerator in a "using" block if dealing with IEnumerable<T>
var e = list.GetEnumerator();
if (e.MoveNext())
{
    var item = e.Current;

    while (e.MoveNext())
    {
        Console.WriteLine("Looping: " + item);
        item = e.Current;
    }
    Console.WriteLine("Last one: " + item);
}
2
ответ дан 7 November 2019 в 12:04
поделиться

Вы должны использовать foreach , только если вы обрабатываете каждый один. Вместо этого используйте взаимодействие на основе индекса. В противном случае вы должны добавить другую структуру вокруг элементов, которую вы можете использовать, чтобы отличать нормальную от последней в вызове foreach (см. Хорошие документы о карте, сокращенной из Google для фона: http: // labs. google.com/papers/mapreduce.html, map == foreach, уменьшенный == например, сумма или фильтр).

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

Обычный трюк - перевернуть список и обработать первый (который теперь имеет известный индекс = 0) , а затем снова примените обратное. (Что элегантно, но не быстро;))

Распространенный трюк - перевернуть список и обработать первый (который теперь имеет известный индекс = 0), а затем снова применить реверс. (Что элегантно, но не быстро;))

Распространенный трюк - перевернуть список и обработать первый (который теперь имеет известный индекс = 0), а затем снова применить реверс. (Что элегантно, но не быстро;))

4
ответ дан 7 November 2019 в 12:04
поделиться

Достаточно ли элегантно? Предполагается, что список не пустой.

  list[0,list.length-1].each{|i|
    puts "Looping:"+i # if not last loop iteration
  }
  puts "Last one:" + list[list.length-1]
22
ответ дан 7 November 2019 в 12:04
поделиться

Foreach элегантен тем, что не заботится о количестве элементов в списке и одинаково обрабатывает каждый элемент. Я думаю, что ваше единственное решение будет использовать цикл for, который либо останавливается на itemcount- 1, а затем вы представляете свой последний элемент за пределами цикла или условие внутри цикла, которое обрабатывает это конкретное условие, то есть if (i == itemcount) {...} else {...}

3
ответ дан 7 November 2019 в 12:04
поделиться

В Ruby я бы использовал each_with_index в этой ситуации

list = ['A','B','C']
last = list.length-1
list.each_with_index{|i,index|
  if index == last 
    puts "Last one: "+i 
  else 
    puts "Looping: "+i # if not last loop iteration
  end
}
13
ответ дан 7 November 2019 в 12:04
поделиться

C # 3.0 или новее

Во-первых, я бы написал метод расширения:

public static void ForEachEx<T>(this IEnumerable<T> s, Action<T, bool> act)
{
    IEnumerator<T> curr = s.GetEnumerator();

    if (curr.MoveNext())
    {
        bool last;

        while (true)
        {
            T item = curr.Current;
            last = !curr.MoveNext();

            act(item, last);

            if (last)
                break;
        }
    }
}

Затем использовать новый foreach очень просто:

int[] lData = new int[] { 1, 2, 3, 5, -1};

void Run()
{
    lData.ForEachEx((el, last) =>
    {
        if (last)
            Console.Write("last one: ");
        Console.WriteLine(el);
    });
}
5
ответ дан 7 November 2019 в 12:04
поделиться

Would it be a viable solution for your case to just take the first/last elements out of your array before doing the "general" each run?

Like this:

list = ['A','B','C','D']
first = list.shift
last = list.pop

puts "First one: #{first}"
list.each{|i|
  puts "Looping: "+i
}
puts "Last one: #{last}"
1
ответ дан 7 November 2019 в 12:04
поделиться

Эту проблему можно элегантно решить, используя сопоставление с образцом в функциональном языке программирования, таком как F #:

let rec printList (ls:string list) = 
    match ls with
        | [last] -> "Last " + last
        | head::rest -> "Looping " + head + "\n" + printList (rest)
        | [] -> ""
1
ответ дан 7 November 2019 в 12:04
поделиться

Я заметил, что ряд предложений предполагает, что вы можете найти последний элемент в списке перед началом цикла, а затем сравнить каждый элемент с этим элементом. Если вы можете сделать это эффективно, то основная структура данных, скорее всего, представляет собой простой массив. Если это так, зачем вообще беспокоиться о foreach? Просто пиши:

for (int x=0;x<list.size()-1;++x)
{
  System.out.println("Looping: "+list.get(x));
}
System.out.println("Last one: "+list.get(list.size()-1));

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

Мне кажется, вы спрашиваете: «Как лучше всего поставить завинтить с помощью молотка? », когда, конечно, лучше задать вопрос:« Какой инструмент лучше всего использовать для ввинчивания шурупа? »

1
ответ дан 7 November 2019 в 12:04
поделиться

Ruby также имеет метод each_index:

list = ['A','B','C']
list.each_index{|i|
  if i < list.size - 1
    puts "Looping:"+list[i]
  else
    puts "Last one:"+list[i]
}

РЕДАКТИРОВАТЬ:

Или используя каждое из них (исправленное решение TomatoGG и Киршштейна):

list = ['A', 'B', 'C', 'A']
list.each { |i|
   if (i.object_id != list.last.object_id)
      puts "Looping:#{i}"
   else
      puts "Last one:#{i}"
   end
}

Looping:A
Looping:B
Looping:C
Last one:A

Или

list = ['A', 'B', 'C', 'A']
list.each {|i| 
  i.object_id != list.last.object_id ? puts "Looping:#{i}" : puts "Last one:#{i}"       
}
2
ответ дан 7 November 2019 в 12:04
поделиться

Вы можете сделать что-то вроде этого (C #):

string previous = null;
foreach(string item in list)
{
    if (previous != null)
        Console.WriteLine("Looping : {0}", previous);
    previous = item;
}
if (previous != null)
    Console.WriteLine("Last one : {0}", previous);
3
ответ дан 7 November 2019 в 12:04
поделиться

Вы можете определить метод eachwithlast в своем классе, чтобы он делал то же, что и each для всех элементов, кроме последнего, но что-то еще для последнего :

class MyColl
  def eachwithlast
    for i in 0...(size-1)
      yield(self[i], false)
    end
    yield(self[size-1], true)
  end
end

Тогда вы могли бы назвать это так ( foo является экземпляром MyColl или его подклассом):

foo.eachwithlast do |value, last|
  if last
    puts "Last one: "+value
  else
    puts "Looping: "+value
  end
end

Изменить: Следуя предложению molf:

class MyColl
  def eachwithlast (defaultAction, lastAction)
    for i in 0...(size-1)
      defaultAction.call(self[i])
    end
    lastAction.call(self[size-1])
  end
end

foo.eachwithlast(
    lambda { |x| puts "looping "+x },
    lambda { |x| puts "last "+x } )
9
ответ дан 7 November 2019 в 12:04
поделиться

Я не знаю, как циклы for-each работают на других языках, кроме java. В java для каждого используется интерфейс Iterable, который используется for-each для получения Iterator и цикла с ним . У Iterator есть метод hasNext, который можно было бы использовать, если бы вы могли видеть итератор внутри цикла. На самом деле вы можете сделать трюк, заключив уже полученный Iterator в объект Iterable, чтобы цикл for получил то, что ему нужно, и вы может получить метод hasNext внутри цикла.

List<X> list = ...

final Iterator<X> it = list.iterator();
Iterable<X> itw = new Iterable<X>(){
  public Iterator<X> iterator () {
    return it;
  }
}

for (X x: itw) {
  doSomething(x);
  if (!it.hasNext()) {
    doSomethingElse(x);
  }
}

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

IterableIterator<X> itt = new IterableIterator<X>(list);
for (X x: itit) {
  doSomething(x);
  if (!itit.hasNext()) {
    doSomethingElse(x);
  }
}
1
ответ дан 7 November 2019 в 12:04
поделиться