Страницы

Поиск по вопросам

Показаны сообщения с ярлыком циклы. Показать все сообщения
Показаны сообщения с ярлыком циклы. Показать все сообщения

пятница, 13 марта 2020 г.

SQL, cursor, перебор, добавляется две записи вместо одной

#sql_server #циклы #cursor


Пытаюсь с помощью курсора перебрать исходные данные и для каждой записи сделать те
или иные изменения. Вот сам запрос:

DECLARE @ID bigint --id attachments
DECLARE @personID BIGINT
DECLARE @territoryServiceID BIGINT
DECLARE @isAtClosed BIT

DECLARE @currentServerDate DATETIME = '2016-01-01 01:10:00.000' --this change GETDATE()
DECLARE @BeginDate DATETIME SET @BeginDate = @currentServerDate
DECLARE @periodYear INT SET @periodYear = DATEPART(YEAR,@currentServerDate) - 1

DECLARE cur cursor LOCAL STATIC
FOR
SELECT at.id, at.personID, at.territoryServiceID, ts.isClosing
FROM Attachments at
INNER JOIN Person p ON p.id = at.personID AND p.parentID IS NULL
INNER JOIN TerritoryServices ts ON ts.id = at.territoryServiceID
LEFT JOIN Attachments at2 ON at2.personID = at.personID AND at2.parentID = at.id
AND at2.attachmentStatusID IN (2,11,12)
WHERE at.attachmentStatusID = 1 AND at.causeOfAttachID = 8 AND at.endDate IS NOT NULL
AND at2.id IS NULL
AND p.id IN (15300000019296419,15300000018501113,15300000014988209,414674754,420940229,409531785)


OPEN cur

FETCH NEXT FROM cur INTO @ID, @personID, @territoryServiceID, @isAtClosed
WHILE @@FETCH_STATUS = 0
BEGIN
DECLARE @personID_NVARCHAR NVARCHAR(MAX) SET @personID_NVARCHAR = CONVERT(NVARCHAR(MAX),@personID)
PRINT '1 ('+@personID_NVARCHAR+')'

IF (@isAtClosed = 1) -- if ter of CA is closing
    BEGIN
        -- Insert error into ErrorHandlingCampainOfAttach
        DECLARE @ErrorDescr NVARCHAR(MAX) SET @ErrorDescr = 'TerId: ' + CONVERT(NVARCHAR(MAX),@territoryServiceID)
        INSERT INTO [dbo].[ErrorHandlingCampainOfAttach] ([AttachmentsID],[personID],[territoryServiceID],[periodYear],[reasonError],[addDate],[description])
        VALUES (@ID, @personID, @territoryServiceID, @periodYear, 1, GETDATE(), @ErrorDescr)
    END
ELSE
    BEGIN
        DECLARE @terAt2ID BIGINT
        DECLARE @isAt2Close BIT = 0
        SELECT @isAt2Close = ts.isClosing, @terAt2ID = ts.id FROM Attachments at 
        INNER JOIN TerritoryServices ts ON ts.id = at.territoryServiceID
        WHERE at.personID = @personID AND at.attachmentStatusID = 2 AND at.endDate
IS NULL

        IF (@isAt2Close = 1) -- if ter of attach is closing
            BEGIN 
                -- Insert error into ErrorHandlingCampainOfAttach
                DECLARE @ErrorDescr2 NVARCHAR(MAX) SET @ErrorDescr2 = 'TerAttachId:
' + CONVERT(NVARCHAR(MAX),@terAt2ID)
                INSERT INTO [dbo].[ErrorHandlingCampainOfAttach] ([AttachmentsID],[personID],[territoryServiceID],[periodYear],[reasonError],[addDate],[description])
                VALUES (@ID, @personID, @territoryServiceID, @periodYear, 2, GETDATE(),
@ErrorDescr2)
            END
        ELSE
            BEGIN 
                BEGIN TRY
                BEGIN TRANSACTION TranName
                    -- Search active request
                    DECLARE @ID_zapros BIGINT 
                    SELECT @ID_zapros = id FROM Attachments WHERE personID = @personID
AND endDate IS NULL AND attachmentStatusID != 2 AND id != @ID
                    IF (@ID_zapros IS NOT NULL) 
                        BEGIN
                            -- Canseled request

                            -- Block #1
                            -- Create cancel for active request
                            INSERT INTO Attachments (personID,orgHealthCareID,personAddressesID,territoryServiceID,attachmentProfileID,doctorID,
                                causeOfAttachID,careAtHome,senderRequestID,senderSystemID,attachmentStatusID,beginDate,endDate,parentID,userID,registratorID,
                                actualAttachmentID,ConflictAttachment,Node,regDate,isMigrated,isDuplicate,oldPersonID,servApplicationID,Num)
                            SELECT at.personID,at.orgHealthCareID,at.personAddressesID,at.territoryServiceID,at.attachmentProfileID,
at.doctorID,
                                8,at.careAtHome,NULL,NULL, 11, @BeginDate, @BeginDate,
at.id, 
                                at.userID, at.registratorID, at.actualAttachmentID,
NULL,NULL,at.regDate,NULL,0,at.oldPersonID,NULL,at.Num
                            FROM Attachments at 
                            WHERE at.id = @ID_zapros

                            -- Set endDate for active request
                            UPDATE Attachments SET endDate = @BeginDate WHERE id
= @ID_zapros
                        END

                    --Search active attach
                    DECLARE @ID_prikrep BIGINT
                    SELECT @ID_prikrep = id FROM Attachments WHERE personID = @personID
AND endDate IS NULL AND attachmentStatusID = 2
                    IF (@ID_prikrep IS NOT NULL) 
                        BEGIN
                            -- Block #2
                            -- Insert detach
                            INSERT INTO Attachments (personID,orgHealthCareID,personAddressesID,territoryServiceID,attachmentProfileID,doctorID,
                                causeOfAttachID,careAtHome,senderRequestID,senderSystemID,attachmentStatusID,beginDate,endDate,parentID,userID,registratorID,
                                actualAttachmentID,ConflictAttachment,Node,regDate,isMigrated,isDuplicate,oldPersonID,servApplicationID,Num)
                            SELECT at.personID,at.orgHealthCareID,at.personAddressesID,at.territoryServiceID,at.attachmentProfileID,
at.doctorID,
                                8,at.careAtHome,NULL,NULL, 8, @BeginDate, @BeginDate,
at.id, 
                                at.userID, at.registratorID, at.actualAttachmentID,
NULL,NULL,at.regDate,NULL,0,at.oldPersonID,NULL,at.Num
                            FROM Attachments at 
                            WHERE at.id = @ID_prikrep

                            --Set endDate for active attach
                            UPDATE Attachments SET endDate = @BeginDate WHERE id
= @ID_prikrep
                        END

                    -- Attach CA
                    INSERT INTO Attachments (personID,orgHealthCareID,personAddressesID,territoryServiceID,attachmentProfileID,doctorID,
                        causeOfAttachID,careAtHome,senderRequestID,senderSystemID,attachmentStatusID,beginDate,endDate,parentID,userID,registratorID,
                        actualAttachmentID,ConflictAttachment,Node,regDate,isMigrated,isDuplicate,oldPersonID,servApplicationID,Num)
                    SELECT at.personID,at.orgHealthCareID,at.personAddressesID,at.territoryServiceID,at.attachmentProfileID,
at.doctorID,
                        8,at.careAtHome,NULL,NULL, 2, @BeginDate, NULL, at.id, 
                        at.userID, at.registratorID, at.actualAttachmentID, NULL,NULL,at.regDate,NULL,0,at.oldPersonID,NULL,at.Num
                    FROM Attachments at 
                    WHERE at.id = @ID

                COMMIT TRANSACTION TranName

                END TRY
                BEGIN CATCH
                    ROLLBACK TRANSACTION TranName

                    -- Insert error into ErrorHandlingCampainOfAttach
                    INSERT INTO [dbo].[ErrorHandlingCampainOfAttach] ([AttachmentsID],[personID],[territoryServiceID],[periodYear],[reasonError],[addDate],[description])
                    VALUES (@ID, @personID, @territoryServiceID, @periodYear, 3,
GETDATE(),ERROR_MESSAGE())
                END CATCH
            END
    END

FETCH NEXT FROM cur INTO @ID, @personID, @territoryServiceID, @isAtClosed
END
CLOSE cur
DEALLOCATE cur


Запрос для курсора возвращает 6 строк(6 выбраны для примера), то есть все ID уникальные,
ничего не задваивается. Далее в зависимости от определенных условий производятся те
или иные действия, прошу обратить внимание на два блока действий (в комментариях называется
Block#1 и Block#2), именно они ведут себя странно. 

После выполнения запроса на какой-нибудь (тут тоже важно, не всегда на одной и той-же
записи, бывает то на одной то на другой, а то и на двух) записи задваиваются строки
с данными, то есть вставляется две строки у которых все данные кроме автоинкрементного
идентификатора повторяются! Причем если откатить действия и попробовать только на этой
записи на одной (то есть цикл прогнать для одной записи) все завершается отлично! Вот
такие-вот злые электрические силы. Непонятно почему так происходит, подскажите кто-нибудь
что не так, или в каком направлении искать решение? 

P.S. триггеров на вставку данных на таблице Attachments нету. Строки всегда вставляются
после всех действия, то есть допустим первое условие выполняется, вставляется строка
1, затем по второму условию вставляется строка 2, затем строка 3, и в случае если происходит
задвоение строки, то она вставляется самой последней, то есть после строки 3 вставляется
строка 4 идентичная строке 1 (или строке 2 когда как)
    


Ответы

Ответ 1



С помощью Mike удалось найти решение данной проблемы! Тут я изложу все поподробнее вдруг кому-то поможет. Итак, начнем. Результат запроса для курсора: ... как видно никакого дублирования идентификаторов нет С подсказкой Mike(спасибо огромное), в одно из полей (Node) записал id записи в переборе, в результате получил следующее: В первой записи все отлично, не будем ее рассматривать. Вторая запись по списку id = 14308060, personID = 414674754. В результате произошло задвоение (Block #1), но в поле Node видим, что в конце записался идентификатор следующей по порядку записи!!! Ниже приведен результат следующей записи: ... тут все нормально Далее.. Пятая запись id = 148362023, personID = 15300000018501113. В результате прошло задвоение (Block #2), опять же в поле Node идентификатор следующей записи Ниже результат следующей записи в которой все ровно: Итак, все это навело на мысль, значения в переменных остаются прежними если в результате установки возвращается NULL, хотя в каждом цикле переменная объявляется заново. Теперь смотрим что происходит: 1. Выполняется обработка второй записи, так как у нее есть активный запрос то следующее выражение: DECLARE @ID_zapros BIGINT SELECT @ID_zapros = id FROM Attachments WHERE personID = @personID AND endDate IS NULL AND attachmentStatusID != 2 AND id != @ID записывает в переменную @ID_zapros идентификатор 150118746, далее выполняется все как нужно, добавляется ровно столько записей сколько нужно, последней записи, которая дублируется еще пока нет! Далее выполняется обработка третьей записи. У данной записи активного запроса нет, поэтому следующее выражение возвращает NULL SELECT @ID_zapros = id FROM Attachments WHERE personID = @personID AND endDate IS NULL AND attachmentStatusID != 2 AND id != @ID но! в переменную @ID_zapros записывается не NULL(как я предполагал), а остается предыдущее значение! Вот тут то и зарыта собака. И получается что при обработке третьей записи добавляется еще одна запись в с данными о предыдущей записи... с 5 и 6 записью все тоже самое, только уже на другом этапе... Я думал что, так как переменная объявляется внутри цикла, то при каждом объявлении в нее будет записываться NULL, также ошибался что при установки переменной, если результат возвращает NULL, то и в переменную запишется NULL, оказалось совсем не так... Решение довольно простое, обнулять переменную принудительно, я сделал так: DECLARE @ID_zapros BIGINT SELECT @ID_zapros = id FROM Attachments WHERE personID = @personID AND endDate IS NULL AND attachmentStatusID != 2 AND id != @ID IF (@ID_zapros IS NOT NULL) BEGIN --Отказываем запрос --Создаем отказ активному запросу INSERT INTO Attachments (personID,orgHealthCareID,personAddressesID,territoryServiceID,attachmentProfileID,doctorID, causeOfAttachID,careAtHome,senderRequestID,senderSystemID,attachmentStatusID,beginDate,endDate,parentID,userID,registratorID, actualAttachmentID,ConflictAttachment,Node,regDate,isMigrated,isDuplicate,oldPersonID,servApplicationID,Num) SELECT at.personID,at.orgHealthCareID,at.personAddressesID,at.territoryServiceID,at.attachmentProfileID, at.doctorID, 8,at.careAtHome,NULL,NULL, 11, @BeginDate, @BeginDate, at.id, at.userID, at.registratorID, at.actualAttachmentID, NULL,@nvar_ID,at.regDate,NULL,0,at.oldPersonID,NULL,at.Num FROM Attachments at WHERE at.id = @ID_zapros --Закрываем дату активному запросу UPDATE Attachments SET endDate = @BeginDate WHERE id = @ID_zapros SET @ID_zapros = NULL END Извиняюсь за довольно большое изложения, но я впервые здесь, может что-то делаю не так вы уж простите! Еще раз спасибо всем кто откликнулся! Надеюсь это кому-нибудь поможет не напороться на те же грабли)

Ответ 2



Код не самый очевидный, не имея данных сложновато понять, что происходит. Как вариант, для отладки вы можете попробовать добавить output inserted.* для всех блоков insert, что даст вам возможность посмотреть в каком порядке и какие именно данные были вставлены. Пример работы output блока: declare @attachments table (id int, status_id int) insert into @attachments (id, status_id) output 'block #1', inserted.* values (1, 2) insert into @attachments (id, status_id) output 'block #2', inserted.* select 3, 8 Возможно, здесь: SELECT @ID_zapros = id FROM Attachments WHERE ... либо здесь SELECT @ID_prikrep = id FROM Attachments WHERE ... по мере движения курсора выбирается не то, что ожидается.

воскресенье, 8 марта 2020 г.

Логический оператор с бесконечным количеством итераций

#java #циклы #операторы


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


Ответы

Ответ 1



Начать исполнять и продолжать пока условие верно: boolean someBoolean = true; while(someBoolean) { //тут можно присвоить false для someBoolean для завершения бесконечного цикла } Либо можно и через цикл for вот так: boolean someBoolean = true; //в цикле for сперва идёт инициализация переменной-чсётчика, в конце действие с ней (инкрементация, например), //а по середине - условие - пока оно верно, цикл будет продолжаться for (;someBoolean;) { //тут можно присвоить false для someBoolean для завершения бесконечного цикла } Если же хотя б одну итерацию надо сделать вне зависимости от начального значения someBoolean, то можно написать так: boolean someBoolean = false; do { //хотя бы раз, но выполнится } while(someBoolean);

Как зациклить функцию, чтобы ее выполнение являлось гарантированным

#python #python_3x #циклы #исключения


Программа обращается к сети интернет для получения данных из списка исходных ID.
Ночью интернет частенько отваливается, что приводит к ошибке программы.
Как добиться безаварийной работы программы, чтобы элемент списка был обработан гарантированно?
Что нужно написать после except:, чтобы программа повторно обращалась к блоку try:,
покуда его не обработает с корректным получением результата y.

data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

def Scan_data(x):
    try:
        y = <..Обращение к интернету..>
    except:
        time.timesleep(60)
        # <..Тут не знаю что написать..>
    return y

for i in data:
    Scan_data(i)

    


Ответы

Ответ 1



Вот где то так. Я также добавил счетчик неуспешних попыток. Если было больше 1000 попыток, то не ведомо, если ли смысл продолжать. data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] def Scan_data(x): y = -1 happy = false tr = 0 # сколько раз пробовали while (!happy and tr < 1000): try: y = <..Обращение к интернету..> happy = true # как только поняли, что все ок except: time.timesleep(60) tr = tr + 1 # кол-во попыток print("попытка номер ", tr) return y for i in data: Scan_data(i)

Ответ 2



Я бы написал так def Scan_data(x): try: y = ... return y except: return None for i in data: while Scan_data(i) is None: time.timesleep(60)

Ответ 3



Примените рекурсию: def Scan_data(x): try: y = <..Обращение к интернету..> except: time.timesleep(60) Scan_data(x) return y

пятница, 28 февраля 2020 г.

Перезапись строки с помощью другой строки, используя цикл for: TypeError: 'str' object does not support item assignment

#python #циклы #for


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

Как я мог бы, используя Питон, перезаписать строку 'splaintext' с помощью 'key'? 


key является аргументом командной строки - argv[1] (строка) 
splaintext - строка, вводимая пользователем


В итоге, если:

splaintext` = 'hello'
key = 'abc'


результатом будет: 'abcab'

Код:

for i in range(len(splaintext)):
    for j in range(len(key)):
        if i == len(splaintext):
            break
        else:
            while True:
                symbol = key[j]
                splaintext[i] =  splaintext[:i] + symbol + splaintext[i+1:]
                i = i + 1
                j = j + 1
                if j == len(key):
                    j = 0
                elif i == len(splaintext):
                    break


Ошибка:

splaintext[i] = splaintext[:i] + symbol + splaintext[i+1:]



  TypeError: 'str' object does not support item assignment

    


Ответы

Ответ 1



Воспользуйтесь itertools.cycle(): from itertools import cycle cycle_gen = cycle(key) res = ''.join([next(cycle_gen) for _ in splaintext]) print(res) Вывод: abcab

Получить индекс элемента в foreach цикле

#java #циклы #foreach


Есть ли возможность в java получить индекс элемента коллекции в цикле foreach?

for (String str: array) {

}


То есть узнать индекс текущего элемента в теле цикла
    


Ответы

Ответ 1



Для работы с индексами стоит использовать обычный цикл for Если "очень хочется", то при условии уникальности элементов массива можно воспользоваться поиском элемента в массиве. Однако этот подход получается всецело хуже обычного for-а: работает за O(n^2), что при большом количестве элементов может создать проблемы с производительностью требует уникальности элементов массива код получается больше и сложнее Так что этот подход можно рассматривать только для полноты картины: List list = Arrays.asList(array); for (String str : array) { int index = list.indexOf(str); ... } Вместо метода List.indexOf можно воспользоваться методом ArrayUtils.indexOf из библиотеки Apache Commons Lang, но суть от этого не меняется - только кода становится чуть меньше Можно ещё использовать дополнительную переменную: int index = 0; for (String str : array) { ... index++; } но это уже получается почти что обычный for

Ответ 2



В Kotlin у коллекций и массивов есть метод forEachIndexed: list.forEachIndexed { element, index -> }

понедельник, 24 февраля 2020 г.

foreach в обратном направлении

#php #массивы #циклы


Можно ли считать информацию с массива, начиная с последнего элемента массива?Количество
данных в массиве неизвестно. Нужно сделать именно циклом foreach.
    


Ответы

Ответ 1



Можно попробовать так: foreach(array_reverse($arr) as $element) { // code } Функция array_reverse

суббота, 15 февраля 2020 г.

Почему ready() всегда выдает true?

#java #циклы


Имеется такой код:

public static void main(String[] args) throws IOException {
      StringReader reader = new StringReader("Khoor Dpljr");
      System.out.println(decode(reader, -3));  //Hello Amigo
}

public static String decode(StringReader reader, int key) throws IOException {
      BufferedReader br = new BufferedReader(reader);
      while (br.ready())
      {
            int b = br.read();
            b = b + key;
            char c = (char) b;
            System.out.println(c);
      }
      return null;
}


Почему ready() всегда выдает true?
    


Ответы

Ответ 1



Потому что так написано в документации к этому методу: True if the next read() is guaranteed not to block for input, false otherwise Перевод: true, если гарантируется, что следующий вызов метода read() будет неблокирующим Так как при достижении конца потока метод read сразу возвращает -1, то и ready() возвращает true. Чтобы код заработал, можно переписать его так: int c; while ((c = bufferedReader.read()) != -1) { // ... } Частичный перевод ответа @StephenC

четверг, 13 февраля 2020 г.

Замена бесконечного цикла

#cpp #циклы


Можно ли заменить следующий бесконечный цикл на обычный цикл? Слышал, что всегда
можно, но не понимаю как.

while (true) {
    if (c1(a)) {
        a = f1(a);
    }

    if (c2(a)) {
        break;
    }

    a = f2(a);
}


Здесь f1, f2 - функции, возвращающие какое-то значение, зависящее от a, c1, c2 -
условия (функции, возвращающие bool), зависящие от a.

upd:

под обычным я понимаю без break, continue, goto и прочих хаков, а чтобы условие было
не постоянным/пустым
    


Ответы

Ответ 1



Заменить можно так do { if (c1(a)) { a = f1(a); } cond = !c2(a); if (cond) a = f2(a); } while (cond); но в данном случае бесконечный цикл нагляднее

Ответ 2



Например можно так. Но я бы не сказал что это улучшит читабельность. for (;!c2(a=!c1(a)?:f1(a));a=f2(a)); Внезапный код-гольф?

Ответ 3



Если вы хотите for (обычный) - то можно просто for(;;) { if (c1(a)) { a = f1(a); } if (c2(a)) { break; } a = f2(a); } Или for(;;a = f2(a)) { if (c1(a)) a = f1(a); if (c2(a)) break; } Мне кажется, что так понятнее всего.

Ответ 4



Если захотите, то можно ещё использовать Go to, но это не советуется использовать. Главное не забывайте, что нужно условие выхода, оно делается через if() { } Самым практичным является while (true) { Тело } Либо for(;;) { }

среда, 12 февраля 2020 г.

Кончилась ли for break'ом

#c_sharp #циклы


Можно ли как-нибудь после выполнения for, проверить, закончился ли цикл сам или его
прервал break?
    


Ответы

Ответ 1



Ввести переменную и перед break ее взводить.

Удалить дубликаты в массиве без использования коллекций. Java

#java #массивы #алгоритм #циклы


Необходимо удалить дубликаты в массиве без использования коллекций. 

C ArrayList или HashSet все понятно, тут делать не чего, но мне задание дали удалить
дубликаты не используя ничего, кроме массивов. При чем метод должен работать, даже
если дубликатов больше двух. 


Исходный массив {1 ,1, 1, 2, 1, 3, 3}
Искомый результат {1, 2, 3}


В общем уже голову сломал, может кто поможет?

Спасибо.
    


Ответы

Ответ 1



Как я полагаю, ваше задание на использование циклов при работе с массивами. Если так, то прямолинейный подход с использованием циклов может выглядеть следующим образом import java.util.*; import java.lang.*; import java.io.*; class Ideone { public static void main (String[] args) throws java.lang.Exception { int[] a = { 1, 1, 1, 2, 1, 3, 3 }; int n = a.length; for ( int i = 0, m = 0; i != n; i++, n = m ) { for ( int j = m = i + 1; j != n; j++ ) { if ( a[j] != a[i] ) { if ( m != j ) a[m] = a[j]; m++; } } } if ( n != a.length ) { int[] b = new int[n]; for ( int i = 0; i < n; i++ ) b[i] = a[i]; a = b; } for ( int x : a ) System.out.print( x + " " ); System.out.println(); } } Вывод программы 1 2 3

Ответ 2



int[] a = new int[] {1, 1, 1, 2, 1, 3, 3}; int[] b = new int[a.length]; int curIndex = 0; for (int i: a) { if (!IntStream.range(0, curIndex).anyMatch(num - > b[num] == i)) { b[curIndex++] = i; } } System.out.println(Arrays.toString(Arrays.copyOf(b, curIndex))); //[1, 2, 3] UPDATE !IntStream.range(0, b.length).anyMatch(num - > b[num] == i) можно заменить следующим методом public static boolean contains(int[] a, int num) { for (int i in a) { if (i == num) { return true; } } return false; } И тогда основной for будет следующим for (int i: a) { if (!contains(b, i))) { b[curIndex++] = i; } }

Ответ 3



@Test public void tt(){ testArray(new int[]{1,2,3,4,5,5,5}); testArray(new int[]{11,12,16,1,2,3,4}); testArray(new int[]{3,3,3,3,3,3,3}); testArray(new int[]{1}); testArray(new int[]{}); testArray(new int[]{10,11,11,11,11,11,11}); testArray(new int[]{1,1,2,2,3,3,4,4}); } public void testArray(int[] a){ Arrays.sort(a); a = removeDuplicates(a); Arrays.stream(a).forEach(value -> System.out.print(value + " ")); System.out.println(); } public int[] removeDuplicates(int[] array){ //Частные случаи if(array.length == 1) return array; if(array.length == 0) return new int[0]; // //Размер больше 1, уникальное значение как минимум одно int unique = 1; for(int i = 1; i < array.length; i++){ if(array[i] != array[i - 1]){ unique++; //Если текущий с предыдущим не равны - значит // увеличиваем счетчик уникальных значений } } int[] result = new int[unique]; //Новый массив нужного размера int k = 0; //Текущая позиция в новом массиве if(result.length > 0){ result[k++] = array[0]; //Пишем в новый массив первое уникальное значение } for(int i = 1; i < array.length; i++){ if(array[i] != array[i - 1]){ result[k++] = array[i]; //Пишем в новый массив остальные уникальные значения } } return result; }

Ответ 4



public void noDubs(){ for (int i = 0; i

Ответ 5



Решил сдал. Завтра узнаем что мне педагог скажет вот такой вариант получился. Шапками не кидать, я второй месяц занимаюсь. Всем большое спасибо за помощь, особенно простые примеры навели на конструктивные мысли. public class DuplicateWithoutCollection { int nulls; /** * Объединяет три метода. * @see #addNullInsteadDuplicate Добавление null вместо дкбликатов * @see #bubbleForNull(String[]) Сортировка null в конец массива * @see #deleteNulls(String[]) Перезапись всех null в новый массив *

* Тест: * @see DuplicateWithoutCollectionTest#WhenArrayWithDuplicatesInThenArrayWithoutDuplicatesOut() */ public String[] finishDeleteDuplicate(String[] arr) { String[] addNull = addNullInsteadDuplicate(arr); String[] bubble = bubbleForNull(addNull); String[] deleteNull = deleteNulls(bubble); return deleteNull; } /** * Заменяет дубликаты на null * Записывает колличество нулей в переменну nulls *

* Тест * @see DuplicateWithoutCollectionTest#WhenArrayWithDuplicateInThenArrayWithNullInsteadDupliateOut() */ public String[] addNullInsteadDuplicate(String[] arr) { for (int i = 0; i < arr.length; i++) { for (int j = i + 1; j < arr.length; j++) { if (arr[i] != null && arr[j] != null && arr[i].equals(arr[j])) { arr[j] = null; nulls++; } } } return arr; } /*** * Выталкиват null в конец массива. *

* Тест * @see DuplicateWithoutCollectionTest#WhenArrayWithNullInThenAllNullsGoToTheEndArray() */ public String[] bubbleForNull(String[] arr) { for (int i = arr.length - 1; i >= 0; i--) { for (int j = 0; j < i; j++) { if (arr[j] == null) { arr[j] = arr[j + 1]; arr[j + 1] = null; } } } return arr; } /** * Удаляет нули. *

* Тест * @see DuplicateWithoutCollectionTest#WhenArrayWithNullInThenArrayWithoutNullOut() * */ public String[] deleteNulls(String[] arr) { String[] result = new String[arr.length - this.nulls]; for (int i = 0; i < result.length; i++) { result[i] = arr[i]; } return result; } }

воскресенье, 9 февраля 2020 г.

Каков механизм изменения значения переменных в цикле for Python

#python_3x #циклы #ссылки


Каким образом изменяется значение списков forenames и surnames, если мы явно не меняем
их значения? Это связано с names, какую роль это играет во внешнем цикле и как добавляя
в него элемент, мы меняем значения списков forenames и surnames? 

def get_forenames_and_surnames():

    forenames = []  
    surnames = [] 

    for names, filename in ((forenames, "forenames.txt"),
                                 (surnames, "surnames.txt")):

        for name in open(filename, encoding='utf8'):
            names.append(name.rstrip())
    return forenames, surnames

    


Ответы

Ответ 1



Для начала пример: a = [1, 2, 3] b = a a.append(4) print(a) print(b) Output [1, 2, 3, 4] [1, 2, 3, 4] Вопрос: почему поменялись оба списка, когда меняли только список a? Ответ: В Python переменные являются ссылками (идентификаторами) на хранящиеся в памяти объекты, поэтому: a = [1, 2, 3] означает - создай объект типа list, заполни его значениями 1, 2, 3 и присвой ссылку на этот объект переменной a. b = a - присвой переменной b ссылку, которая хранится в переменной a (которая в свою очередь указывает на объект). Теперь две переменных указывают на один и тот же объект. a.append(4) - найди объект по ссылке в переменной a и добавь в него элемент 4. Помним, что объект у нас один, на него указывают a и b. Если сделаем b.append(4), результат будет такой же. Упрощённая схема связи переменных и объектов: Теперь разберём ваш код: # Вспомогательная функция для печати идентификатора объекта def print_object_id(var_name, obj): # Функция id возвращает идентификатор объекта. obj_id = id(obj) print('{:X} - "{:s}" id'.format(obj_id, var_name)) def get_forenames_and_surnames(): print("===Назначение переменных===") forenames = [] # Печатаем, какой идентификатор присвоился переменной forenames print_object_id("forenames", forenames) surnames = [] # Печатаем, какой идентификатор присвоился переменной surnames print_object_id("surnames", surnames) print("\n===Внешний цикл for===") for names, filename in ((forenames, "forenames.txt"), (surnames, "surnames.txt")): ### На каждой итерации переменной "names" присваивается новый идентификатор: # В первой итерации это идентификатор переменной forenames # Вo второй итерации это идентификатор переменной surnames print_object_id("names", names) for name in open(filename, encoding='utf8'): # По идентификатору хранящемся в "names", Python ищет у # себя объект (в нашем случае это объект типа List) # и вызывает у этого объекта метод "append". # В итоге, новой элемент добавляется к списку. names.append(name.rstrip()) return forenames, surnames get_forenames_and_surnames() Output ===Назначение переменных=== 7F552E85B388 - "forenames" id 7F552E85B3C8 - "surnames" id ===Внешний цикл for=== 7F552E85B388 - "names" id ### Тот же самый, что и у forenames 7F552E85B3C8 - "names" id ### Тот же самый, что и у surnames

Ответ 2



Наиболее сложной является команда for names, filename in ((forenames, "forenames.txt"), (surnames, "surnames.txt")): То, что за in, есть кортеж из 2 элементов: (forenames, "forenames.txt") (первый элемент) (surnames, "surnames.txt") (второй элемент) Значит, тело цикла будет повторяться только дважды: первый раз для names == forenames и filename == "forenames.txt" второй раз для names == surnames и filename == "surnames.txt" В каждой из этих итераций выполнится тело цикла: for name in open(filename, encoding='utf8'): names.append(name.rstrip()) Значит, в первой итерации откроется файл forenames.txt и строки из него добавятся к списку forenames, в другой то же самое с файлом surnames.txt и списком surnames.

понедельник, 3 февраля 2020 г.

Редактирование дата-фрейма, содержащего NA

#циклы #r


Проблема заключается в следующем:

Имеется дата-фрейм, в котором необходимо заменить NA на значение, содержащееся в
предыдущей строчке.

В случае с вектором данная проблема решается прогонкой цикла по вектору, однако для
редактирования дата-фрейма данный способ не подходит.
    


Ответы

Ответ 1



В пакете zoo есть функция na.locf которая делает именно это: > df <- data.frame(a=c(1,NA,2,NA,NA), b=c(1.3,NA,2.4,NA,1.1)) > df a b 1 1 1.3 2 NA NA 3 2 2.4 4 NA NA 5 NA 1.1 > na.locf(df) a b 1 1 1.3 2 1 1.3 3 2 2.4 4 2 2.4 5 2 1.1

воскресенье, 2 февраля 2020 г.

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

#java #массивы #циклы


Нужно создать пустой массив из 10 целых чисел и с помощью цикла заполнить его значениями,
каждое из которых будет на 3 больше предыдущего (начиная с 1), то есть получить [1,
4, 7, 10, 13, 16, 19, 22, 25, 28].

Написал такой код:

public class massiv {

    public static void main(String[] args) {
        int[] array = new int[10];
        array[0] = 1;
        for (int i = 0; i < array.length; i++) {
            array[i] = array[i] + 3; //вот тут туплю - не пойму как решить
            System.out.println(array[i]);
        }
    }
}


Как правильно заполнить массив?
    


Ответы

Ответ 1



Цикл со второго элемента массива. public static void main(String[] args) { int[] array = new int[10]; array[0] = 1; for (int i = 1; i < array.length; i++) { array[i] = array[i - 1] + 3;//вот тут туплю - не пойму как решить System.out.println(array[i]); } } До начала цикла мы присваиваем значение элементу [0]. Затем начинаем цикл с элемента [1]. На каждом шаге итерации мы используем предыдущий элемент для добавления к нему 3 и присвоения следующему элементу. Так цикл работает: array[1] = array[0] + 3. Получаем array[1] = 4. Потом array[2] = array[1]+3. Получаем array[2] = 4+3 = 7, ну и т.д.

Ответ 2



Так как заданную рекурсивную функцию F(0) = 1; F(n) = F(n - 1) + 3; Можно заменить на нерекурсивную: F(n) = n * 3 + 1; То можно сделать чуть короче с привязкой значения к номеру итерации (i): int[] array = new int[10]; for (int i = 0; i < array.length; i++) { array[i] = i * 3 + 1; } А в случае использования Java 8: int[] array = IntStream.range(0, 10).map(e -> e * 3 + 1).toArray();

Ответ 3



array[i] = array[i]+3;//вот тут туплю - не пойму как решить да, именно тут загвоздка, Вы, вероятно, хотите увеличить значение предыдущего элемента на 3. Для этого можно сделать так: array[i] = array[i-1]+3; Однако, в этом случае нужно начать цикл не с нулевого элемента array[0], а с первого array[1], потому как элемента array[i-1] (т.е. array[0-1]) не существует

Ответ 4



public static void main(String[] args) { int[] array = new int[10]; int value = 1; for (int i = 0; i < array.length; i++) { array[i] = value; value += 3; System.out.println(array[i]); } }

Ответ 5



for (int i = 0; i < array.length; i++) { for (int i = 1; i < array.length; i++) { array[i] = array[i] + 3; array[i] = array[i-1] + 3;

Несколько init-expression в for

#cpp #циклы


#include 
#include 
#include 
#include 

using namespace std;

int Search(string* Array, int Size, string* Words) {
    ifstream *Read = new ifstream[Size];

    for (int I = 0; I < Size; I++) {
        Read[I].open(Array[I]);
        if (!Read[I]) {
            cout << "Файл с именем: " << Array[I] << "не может быть открыт \n";
        }
        // В следующей строке в возникает ошибка I должно иметь константное значение
        //Ошибки нет, если "string Value" вынести из цикла
        //Почему возникает ошибка ?
        for (string Value, Read[I] >> Value; !Read[I].eof(); Read[I] >> Value) {
            // Что-то делающий код
        }

    }

    for (int I = 0; I < Size; I++) {
        Read[I].close();
    }
}

    


Ответы

Ответ 1



В синтаксисе for     for ( init-statement conditionopt ; expressionopt ) statement первая часть - init-statement - является либо выражением, либо объявлением. Вы изначально использовали синтаксис string Value, [...], который явно говорит, что в вашем случае в качестве init-statement вы хотите использовать именно объявление, а не выражение. Однако дальнейший синтаксис [...], Read[I] >> Value не является корректным синтаксисом объявления. Отсюда и ошибка. (Странно, что вы в своем вопросе называете эту часть синтаксиса for "init-expression", хотя в вашем же примере это никакой не expression.) Выбирайте: либо выражение, либо объявление. Перемешать выражение с объявлением вот так вот в лоб, как у вас, не получится.

Ответ 2



for (string Value, Read[I] >> Value; !Read[I].eof(); Read[I] >> Value) { Да, так нельзя, потому что Read[I] >> Value - это не объявление переменной. Можно так: for (string Value; Read[I] >> Value, !Read[I].eof(); ) { В коде баг и нужно так: for (string Value; Read[I] >> Value; ) {

Прогон в foreach с изменением количества элементов

#c_sharp #многопоточность #циклы #foreach #parallel


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

Вначале думал про for и если удаляем, делать i--, т.к. уменьшилось количество элементов
на 1, но это не сделать при параллельном прогоне, поэтому думаю сделать подобное в
foreach, чтобы не привязываться к индексу элемента. Но при изменение foreach выскакивает
исключение, что логично.

Можно ли как-нибудь прогнать параллельно по циклу и по условию, если что удалить
элемент. Чтобы это не сказывалась на других элементах в параллельных потоках?
    


Ответы

Ответ 1



Если удалять элемент из коллекции сразу же на месте не требуется — заведите еще одну (потокобезопасную) коллекцию, элементы подлежащие удалению складывайте в нее, после завершения первого цикла просто удалите из первой коллекции все элементы, присутствующие во второй: // заводим коллекцию var forRemoving = new ConcurrentBag(); foreach (var item in items) { ... // складываем в нее элементы подлежащие удалению forRemoving.Add(item); } // удаляем foreach (var item in forRemoving) items.Remove(item); Если для вашей задачи не принципиально удаление элементов из входной коллекции, а подойдет также вариант с формированием новой коллекцией — можно воспользоваться функционалом Parallel Linq: var result = items.AsParallel() .Where(item => condition(item)) .ToList();

Ответ 2



У меня есть список. Если список - это именно List, то используй обычный цикл for. Обращаю внимание, что удаление нескольких элементов через Remove неэффективно, поскольку приведёт к квадратичной асимптотике (хвост всё время сдвигается). Правильным вариантом было бы использовать метод RemoveAll. Ну либо написать обраотку списка в один проход с ручным сдвигом конца по мере порверки.

Как достать строку из массива который является значением ключа объекта?

#javascript #массивы #циклы #объекты




// Программа поиска операторов мобильной связи Украины
"use strict";
// Создаем объект с значениями ключей-массивами(коды операторов) 
var mobile = {
  Kyivstar: ["039", "067", "068", "096", "097", "098"],
  Vodafone: ["050", "066", "095", "099"],
  Lifecell: ["063", "093"],
  Intertelecom: ["094"],
  PEOPLEnet: ["092"],
  TriMob: ["091"]
}
// Запрашиваем у пользователя номер мобильного телефона
var user = prompt("Введите номер мобильного телефона в формате: 000 1112233", "");
// Получаем доступ к первым 3-м индексам user
var x = user.substr(0, 3);
// Прогоняем в цикле все ключи
for (var key in mobile) {
  var arr = mobile[key];
  // Проходимся по всем массивам
  var check = arr.forEach(function (item, i, arr) {
    if (x === item) {
      //Выводим пользователю результат
      alert("Вас приветствует " + key);
    } 
  }); 
}




Задача была такая:  

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

Я не совсем уверен в правильности решения данной задачи.
Вроде все работает, а правильно ли?
    


Ответы

Ответ 1



Вставил из старой проверки своей с сайта, может пригодится: // Создаем объект с значениями ключей-массивами(коды операторов) var mobile = { Kyivstar: ["039", "067", "068", "096", "097", "098"], Vodafone: ["050", "066", "095", "099"], Lifecell: ["063", "093"], Intertelecom: ["094"], PEOPLEnet: ["092"], TriMob: ["091"] } // Запрашиваем у пользователя номер мобильного телефона var user = prompt("Введите номер мобильного телефона", ""); var x; var y = -1; user = getTelNums(user); switch (user.length) { case 10: y = 0; break; case 11: y = 1; break; default: alert('неверный формат'); break; } if (y >= 0) { // Получаем доступ к первым 3-м индексам user var x = user.substr(y, 3); // Прогоняем в цикле все ключи var op = "Неизвестный оператор"; for (var key in mobile) { var arr = mobile[key]; // Проходимся по всем массивам var check = arr.forEach(function(item, i, arr) { if (x === item) { op = key; return; } }); } //Выводим пользователю результат alert('Вас приветствует '+op); } function getTelNums(telStr) { var regexpNums = /\d/g; var regexpTel = /^([7|8]{0,1}0\d{2})?\d{7}$/; var resultTel = ""; var checkNums = telStr.match(regexpNums); // из строки пользователя получаем массив цифр if (checkNums) { // если массив не пустой // сделаем из него строку: for (var j = 0; j < checkNums.length; j++) resultTel += checkNums[j]; // проверим, телефон ли это: if (!regexpTel.test(resultTel)) { resultTel = ""; } } return resultTel; }

В каких случаях рекурсия более эффективна итерации ? (java)

#java #циклы #рекурсия


В каких случаях рекурсия более эффективна итерации ? (java)
    


Ответы

Ответ 1



Однозначно, когда работаете с древовидными структурами и вы не знаете сколько вложенностей. И без рекурсии вам никак по нему не пройти.

Ответ 2



Все, что можно решить рекурсией, можно решить итерацией. Но дополнительный минус рекурсии состоит в том, что при ее использовании аппаратный стек системы проваливается все глубже и для больших наборов данных это чревато падением приложения. Так что практического смысла рекурсия не имеет, только как учебная задача с целью более полного осознания возможностей программиста. Пользуйтесь циклом и Ваш стек никогда не провалится. А если ваши промежуточные данные надо укладывать в контейнер-стек, то его переполнение можно контролировать программно, в отличие от аппаратного стека системы.

пятница, 31 января 2020 г.

Цикл for с пошаговой итерацией на javascript

#javascript #jquery #циклы


Подскажите, как исправить код, чтобы при каждом клике по btn_refresh запускался цикл
и в консоле выводился результат. Т.е. первый клик > выводит "one", второй клик > выводит
"two", третий клик > выводит "three".

В данный момент выводятся одновременно 3 варианта.

    var btn_refresh=$("#review__content__refresh"),
        fullReviewArray=[0,1,2];

    btn_refresh.click(function(){  
      for(var i = 0; i < 3; i++) 
    {if(i==0){
             console.log("one");
    }
    else if(i==1){
             console.log("two");
    }
    else if(i==2){
             console.log("three");
    } 
    }//конец for
    });//конец click to btn_refresh

    


Ответы

Ответ 1



Непонятно, зачем цикл. var btn_refresh = $("#review__content__refresh"); btn_refresh.click(function() { var counter = this.clickCounter; if (counter) this.clickCounter = counter + 1; else this.clickCounter = 1; if (this.clickCounter > 3) this.clickCounter = 1; switch (this.clickCounter) { case 1: console.log("one"); break; case 2: console.log("two"); break; case 3: console.log("three"); break; default: console.log("not in [1,2,3]"); } }); //конец click to btn_refresh

Ответ 2



Можно еще и так: 'use strict'; function* num() { var values = ['one', 'two', 'three']; var i = 0; while (i < 3) { yield values[i]; i++ } } function showNext() { console.log(iterator.next().value); } const iterator = num();

Ответ 3



на native js если интересно с использованием делегирования событий - http://codepen.io/tokamame/pen/rmzzOK?editors=1010 document.addEventListener("load", onLoad()); var but = document.getElementById('button'); var clear = document.getElementById('clear'); var out = document.getElementById('output'); var counter = 1; function onLoad() { document.addEventListener("click", showClick); } function showClick(e) { if (e.target.innerHTML === "Кликни меня") { out.innerHTML = 'Вы нажали на кнопку "Кликни меня" ' + counter + ' раз'; counter++; } else if (e.target.innerHTML === "Очистить счетчик") { out.innerHTML = 'Вы ни разу ни кликали'; counter = 1; } else { console.log('Что-то пошло не так'); } }
Вы ни разу ни кликали


Ответ 4



Ещё вариант) let btn = document.querySelector('button'); let out = document.querySelector('output'); btn.addEventListener('click', function() { let i = btn.i || 0; console.log(`${i%3+1} ticks`) btn.i = ++i; }); С one/two/three: let btn = document.querySelector('button'); let out = document.querySelector('output'); let map = ['one', 'two', 'three']; btn.i = 0; btn.addEventListener('click', function() { btn.i %= 3; console.log(map[btn.i++]) });

среда, 29 января 2020 г.

Какой из вариантов циклов быстрее?

#c #циклы #cpp #php


Есть блоки кода вычислений блок1, блок2, блок3, блок4,...блок 10, скажем. Скажите,
как поступить при использовании их в цикле:
for (i = 0; i <= n; i++) {
    блок1;
    блок2;
    блок3;
    блок4;
    ...
    блок10;
}

Или же так оптимально:
for (i = 0; i <= n; i++) {
    блок1;
}

for (i = 0; i <= n; i++) {
    блок2;
}

.............

for (i = 0; i <= n; i++) {
    блок10;
}

Можете объяснить почему? Мне лично кажется, что первый вариант быстрый и правильный.    


Ответы

Ответ 1



Ответ скорее не ТС, а @IronVbuf. Начало развернутого комментирования его ответа. Копия моего комментария: @IronVbif, рассуждения красивые. Время позднее, не хочу (сейчас) все разбирать. Если правильно понял, в пунктах 4, 5 и 6 Вы склоняетесь к тому, что несколько маленьких циклов (особенно если их тела маленькие) будут производительней одного. Практический замер (gcc -O3 MinGW (32-bit) Windows 7 64-bit I5-2500 3.3GHz) показал обратное (причем аж в 3 раза для 6 циклов и 10^9 повторов маленьких вычислений (преобразование int->double, double умножение и сложение) Примерчик (нисколько не претендует на полноту, 5 минут на коленке). gcc -O3 MinGW (32-bit) Windows 7 64-bit I5-2500 3.3GHz #include #define incvar(x,y) {x = x + i*y;} main (int ac, char *av[]) { double a = 0, b = 0, c = 0, d = 0, e = 0, f = 0; int i; if (av[1]) { printf ("one loop\n"); for (i = 0; i < 1000000000; i++) { incvar(a,1.234); incvar(b,7.234); incvar(c,11.234); incvar(d,111.234); incvar(e,51.234); incvar(f,21.234); } } else { printf ("six loops\n"); for (i = 0; i < 1000000000; i++) incvar(a,1.234); for (i = 0; i < 1000000000; i++) incvar(b,7.234); for (i = 0; i < 1000000000; i++) incvar(c,11.234); for (i = 0; i < 1000000000; i++) incvar(d,111.234); for (i = 0; i < 1000000000; i++) incvar(e,51.234); for (i = 0; i < 1000000000; i++) incvar(f,21.234); } printf ("%e %e %e %e %e %e\n",a,b,c,d,e,f); } c:/Users/avp/src/cc/hashcode $ gcc -O3 bloloops.c c:/Users/avp/src/cc/hashcode $ date; ./a; date Mon Aug 13 23:55:42 2012 six loops 6.170000e+017 3.617000e+018 5.617000e+018 5.561700e+019 2.561700e+019 1.061700e+019 Mon Aug 13 23:56:00 2012 c:/Users/avp/src/cc/hashcode $ date; ./a 1; date Mon Aug 13 23:56:17 2012 one loop 6.170000e+017 3.617000e+018 5.617000e+018 5.561700e+019 2.561700e+019 1.061700e+019 Mon Aug 13 23:56:23 2012 c:/Users/avp/src/cc/hashcode $ Все желающие приглашаются к экспериментированию (вместо теоретизирования на основе прочитанной литературы) с последующим обсуждением результатов. UPDATE Для замера времени исполнения фрагментов программы удобно использовать функцию: /* avp время в миллисекундах */ #include #include long long mtime() { struct timeval t; gettimeofday(&t, NULL); long long mt = (long long)t.tv_sec * 1000 + t.tv_usec / 1000; return mt; } Меряем так: ... long long mtime(void); ... long long start = mtime(); // измеряемый код ... printf ("duration: %lld msec\n",mtime()-start); ...

Ответ 2



Можно перефразировать вопрос так: "Есть процедура1 и процедура2. Какая работает быстрее?". Очевидно, что выбор реализации надо решать на конкретном коде, потому что смоделировать в голове сложный процессор с кучей фишек вроде реордеринга и префетча нереально. Так что тестить, тестить и еще раз тестить. Мои соображения: Первый вариант (Убер-цикл) хорош для маленьких несвязных кусочков или слабо-связных (не связность вычислений вообще всегда хорошо). В этом случае сведется к минимуму кеш-миссы (Предполагаем что мало кода дергает мало памяти). Реордеринг инструкций и конвейер позволит добиться параллелизма на уровне АЛУ при выполнении инструкций. Для обратной ситуации в убер-цикле, когда много кода (и он скорее всего дергает кучу разной памяти) можно убить хардварный префетч и потерять много на кеше. Товарищ avp сказал про выгрузку\загрузку страниц, но это уже макроуровень. Сложно представить код, который должен выполнится туеву хучу раз и каждая итерация при этом так нагружает менеджер памяти. Если данные сильносвязаны, то будет совсем все плохо, если же нет - то можно ожидать частичного паралелизма некоторых инструкций. Куча маленьких циклов будет хороша для большого количества данных (используемых в каждом блоке). С одной стороны всегда четко отрабатывает префетч и кеш (Насколько это возможно, потому что все что вы будете дергать нужно именно этому блоку), но при этом спариться инструкции между итерациями не смогут (скорее всего). Потеря производительности на инструкциях не страшна, поскольку лучше всегда выигрывать в обращении к памяти. В ряде случаев компилятор может построить код для векторного сопроцессора (работает в случае простых циклов с маленькими блоками, отсюда же понятно почему для убер-цикла шанс векторизации меньше). Вариант с хардварным анроллом. Если цикл совсем мал и он попадает под определенные паттерны, то его может развернуть сам процессор. Производительность при срабатывании этой фичи серьезно подскакивает. Загвоздка в том что нет рекомендаций по тому, как писать код для этой фичи (В одном из докладов видел сложное объяснение почему этим нереально пользоваться на практике). Анролл компилятором (или вручную). Компилятору будет проще развернуть (при указании опции это сделать) простой маленький цикл, чем громадный и непонятный. После правильного анролла вручную можно повысить шанс генерирования кода для векторного процессора. Вариант когда несколько циклов будет работать медленней придумать сложно, но можно предположить что оверхед от инкрементов переменной i и сравнений будет сравним с временем выполнения цикла. Но скорей всего такой цикл заанролится или векторизуется компилятором, поскольку он очень простой. Естественно для интерпретируемых языков это все не будет работать. Насколько я понимаю, для них чем меньше кода, тем лучше. Ну вот такая вот простынка. Замечания приветствуются.

Ответ 3



В случае независимых блоков можно получить выигрыш с помощью второго варианта, разместив каждый цикл в своём потоке. Если же последовательность выполнения блоков важна это вряд-ли получится. Если использование многопоточности не подразумевается (я бы не стал надеется, что умный компилятор или интерпретатор сделает это за вас), первый вариант выглядит предпочтительней, так как: Обслуживание каждой итерации цикла - это как минимум несколько процессорных команд (инкремент счётчика, переход на адрес) В ряде языков каждая итерация может также неявно обкладываться управляющими конструкциями типа try/catch/finally. Пример приведён на PHP, а это язык интерпретируемый, больший скрипт дольше компилируется, а это тоже время. Так или иначе, я бы в первую очередь обратил внимание на читабельность кода. Оптимизацию по скорости целесообразно проводить только для "узких мест". Первый вариант, безусловно, читается лучше, особенно, если тело цикла выделить в отдельную функцию.

Ответ 4



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

Как определить последнюю итерацию цикла for?

#циклы


Часто бывает нужно определить последнюю итерацию цикла. Как это лучше сделать?
    


Ответы

Ответ 1



Вычисление каждый раз for (i = 0; i < m_i; last = ((++i + 1) === m_i)) { abc(); if (last) efg(); xyz(); } Вычисление один раз last = false; for (i = 0; (i < m_i - 1) || (last = !last); i++) { abc(); if (last) efg(); xyz(); } Разнесённая обработка for (i = 0; i < m_i - 1; i++) { abc(); xyz(); } if (i < m_i) { abc(); efg(); xyz(); } Редкий, но идеальный случай: for (i = m_i - 1; i >= 0; --i) { abc(); if (!i) efg(); xyz(); }

Ответ 2



В общем случае - никак. Цикл for управляется предикатом, который теоретически может иметь любую внутреннюю логику. Однако если для переменной цикла возможно объявить функцию next(), которая будет возвращать следующее значение, то возможно сделать такой трюк (C++): #include #include using namespace std; string::iterator next(string::iterator i) { return ++i; } main() { string nums = "12345"; for (string::iterator i = nums.begin(); i != nums.end(); ++i) { if (next(i) != nums.end()) cout << *i << endl; else cout << *i << " (это последняя)" << endl; } }

Ответ 3



Вычислить условие в самом теле. for(инициализация; условие; инкремент) { if (!условие) (выйти из цикла) } А еще можно сделать цикл бесконечным и выходить из него через if #define ever ;; for(ever) { if (условие выхода) (выйти из цикла) }

Ответ 4



А если не пытаться определять последнюю итерацию цикла, а сознательно "прыгнуть" в нее? int i; for(i=0; i < n; i++) { System.out.println("For cycle iteration="+i); } //сознательно прыгаем в последнюю итерацию цикла i--; //после завершения цикла i=n System.out.println("Last iteration again"+i);

Ответ 5



Во многих языках принцип одинаков: for() содержит три выражения, первое из которых выполняется в начале, второе выполняется перед итерацией, если возвращает TRUE, третье - после итерации. Можно прямо в этих выражениях узнавать, последняя ли итерация грядёт. Напр. на PHP: for( $i=0; $i<=10; $last = $i++ == 10) { if( $last) { // последний раунд } // обычные действия }