for 루프 주석에이 추가 변수를 사용하면 어떤 이점이 있습니까?


11

내가 작업중 인 큰 프로젝트 (의사 코드)에서 다음 루프 주석을 발견했습니다.

var someOtherArray = [];
for (var i = 0, n = array.length; i < n; i++) {
    someOtherArray[i] = modifyObjetFromArray(array[i]);
}

내가 주목 한 것은이 여분의 "n"변수입니다. 나는 이런 식으로 작성된 lop을 본 적이 없다.

분명히이 시나리오 에서이 코드를 다음과 같은 방식으로 작성할 수없는 이유는 없습니다 (매우 익숙합니다).

var someOtherArray = [];
for (var i = 0; i < array.length; i++) {
    someOtherArray[i] = modifyObjetFromArray(array[i]);
}

그러나 나는 생각했다.

그러한 for 루프를 작성하는 것이 의미가있는 시나리오가 있습니까? for 루프 실행 중에 "배열"길이가 변경 될 수 있지만 원래 크기보다 더 루프를 반복하고 싶지는 않지만 그러한 시나리오는 상상할 수 없습니다.

OutOfBoundsException이 발생할 가능성이 높으므로 루프 내부에서 배열을 축소하는 것도 의미가 없습니다.

이 주석이 유용한 알려진 디자인 패턴이 있습니까?

편집 @ Jerry101이 지적한 바와 같이 그 이유는 성능입니다. : 여기가 생성 한 성능 테스트에 대한 링크입니다 http://jsperf.com/ninforloop가 . 내 의견으로는 당신이 매우 큰 배열을 반복하지 않는 한 차이는 충분히 크지 않습니다. 내가 복사 한 코드는 최대 20 개의 요소 만 가지고 있었 으므로이 경우 가독성이 성능 고려 사항보다 중요하다고 생각합니다.


편집에 대한 반응 : 이것은 객체 지향 프로그래밍입니다. 표준 배열 길이는 빠르고 저렴합니다. 그러나 어떤 이유로 든 .length 구현은 비싼 것으로 바뀔 수 있습니다. 값이 동일하게 유지되면 여러 번 얻지 마십시오.
피터 B

나는 동의한다. 이 옵션에 대해 아는 것이 좋지만 SQL 쿼리와 비슷한 예를 얻지 않으면 자주 사용하지 않을 것입니다. you☺ 감사
블라드 Spreys

배열이 백만 개의 항목 인 경우 값이 동일하게 유지되는 동안 1 번이 아닌 백만 번 array.length를 호출합니다. 백만 번 무언가를 요구하고 각각의 후속 답변이 첫 번째 답변과 동일하다는 것을 알고 있습니다.
피터 B

1
이로 인해 코드를 읽기가 훨씬 어렵다는 것을 알 수 없습니다. (심지어, 누군가가 그런 간단한 루프에 어려움을 겪고 있다면 걱정해야합니다.) 1) 40 년이 넘는 C 및 C-decended 언어 후에도 모든 심각한 컴파일러가 아직이 작업을 수행하지 않았다면 정말 놀랐습니다. 당신을 위해; 그리고 2) 이것은 핫스팟이 아닐 수도 있습니다. 라이브러리 내부에 있지 않는 한 (예 : 데이터 구조 구현) 누군가 5 초를 추가로 파싱하는 데 가치가없는 것 같습니다
Doval

1
C # /. NET에서는 JITter가 배열 범위 검사를 제거 할 수 있음을 알지 못하므로 n사용하는 변형이 사용하는 변형보다 느릴 수 있습니다 array.Length.
코드 InChaos

답변:


27

변수 n는 생성 된 코드가 모든 반복에 대해 배열 길이를 페치하지 않도록합니다.

사용 된 언어, 배열이 실제로 컬렉션 개체인지 JavaScript "배열"인지 여부 및 기타 최적화 세부 사항에 따라 런타임에 차이를 만들 수있는 최적화입니다.


3
아닙니다. 배열의 길이가 모든 반복을 가져 오는지 여부는 언어뿐만 아니라 컴파일러 및 컴파일러 옵션 및 루프에서 수행되는 작업 (C 및 C ++에 대해 이야기하고 있음)에 따라 달라집니다.
BЈовић

.. 그럼에도 불구하고, 내가 정말로 원한다면 루프 할당 바로 위에 개인적으로 n 할당을 넣을 것입니다 .OP가 지적했듯이 이것은 사용하기가 드문 (YMMV) 구조이므로 다른 개발자가 쉽게 읽지 못하거나 이해할 수 없습니다. 코드.
교체

20
작성된 바와 같이, n루프의 범위 는 일반적으로 좋은 것입니다. 나중에 다시 사용하려는 경우에만 루프 전에 정의합니다.
Jerry101

4
@ Jerry101 : 분명히 예제 스 니펫은 JavaScript이며 루프 범위와 같은 것은 없습니다.
Bergi

1
@ BЈовић : 실제로 컴파일러는 배열 크기가 변하지 않는다는 것을 거의 증명하지 않습니다 (일반적으로 루핑중인 벡터가 함수의 로컬이고 루프에서 인라인 된 함수 만 호출하는 경우에만 사소하게 입증 가능합니다).
Matteo Italia

2

배열의 길이를 가져 오는 것은 반복하는 실제 동작보다 쉽게 ​​"더 비싸다".

따라서 세트가 변경되지 않으면 길이를 한 번만 쿼리하십시오.

배열이 아니라 SQL Server에서 레코드 세트를 사용하면 매번 반복 할 때마다 레코드 수를 쿼리하지 않으므로 크게 향상되었습니다. (물론이 프로세스 중에 배열 또는 레코드 세트가 변경되지 않도록 보장 할 수있는 경우에만이 작업을 수행하십시오).


레코드 수가 변경되면 어떻게해야합니까? 100 개의 항목이 있다고 가정하고 항목 50을 처리하는 동안 # 25 이후의 항목이 삽입됩니다. 따라서 # 51 항목을 처리 할 때 이미 처리 한 # 50과 동일하며 문제가 발생합니다. 문제는 길이가 변하는 것이 아니라 훨씬 더 널리 퍼져 있다는 것입니다.
gnasher729

@ gnasher729 일단 비대칭 행동에 빠지면 잘못 될 수있는 것이 많이 있습니다. 그러나 시작 및 SQL 트랜잭션과 같은 것에 대해 할 수있는 일이 있습니다.
피터 B

2

for 루프 실행 중에 "배열"길이가 변경 될 수 있지만 원래 크기보다 더 루프를 반복하고 싶지는 않지만 그러한 시나리오는 상상할 수 없습니다.

퍼포먼스에 대해 이야기하는 사람들은 아마도 이것이 그렇게 쓰여진 이유 일 것입니다.

그러나 귀하의 질문에 대한이 부분에 답하기 위해 루프의 주요 목적이 반복되는 배열을 수정하는 것이 발생할 가능성이 가장 큽니다. 의사 코드에서 다음과 같은 것을 고려하십시오.

guests = [];
for (i = 0; i < invitations.length; ++i) {
    if (! invitations[i].is_declined()) {
        guests.append(invitations[i].recipient())
    }
}
// maybe some other stuff to modify the guestlist
for (i = 0, n = guests.length; i < n; ++i) {
    if (guests[i].has_plus_one()) {
        guests.append(guests[i].get_plus_one());
    }
}

물론 다른 방법으로 쓸 수도 있습니다. 이 경우 수신자가 초대를 수락했는지 여부를 확인하는 동시에 플러스 플러스를 확인하고 한 번에 한 명씩 전체 참석자 목록을 만들 수있었습니다. 필자는이 두 가지 작업을 반드시 결합하고 싶지는 않지만 이것이 왜 틀린지 즉시 생각할 수 없으므로이 디자인이 필요합니다 . 때때로 고려하는 옵션입니다.

실제로이 코드에서 가장 잘못된 것은 guests배열의 멤버 자격이 코드의 다른 지점에서 다른 것을 의미한다는 것입니다. 따라서 나는 확실히 이것을 "패턴"이라고 부르지 않을 것이지만, 이런 종류의 일을 배제하는 것이 결함이 충분하다는 것을 모른다.


다른 스레드에서 배열을 수정할 수도 있습니다. 이것은 컴파일러가 길이 검색을 최적화하지 못하게합니다. 따라서 프로그래머는 분명히 다른 스레드에서도 배열이 변경되지 않는다고 말합니다.
Basilevs

0

가능하면 배열의 모든 요소를 ​​순회하는 반복자를 사용해야합니다. 임의 액세스 스토리지가 아닌 시퀀스로만 배열을 사용하므로 순차 액세스를 수행하는 반복기가 더 빠를 것입니다. 배열이 실제로 이진 트리라고 생각한다고 상상해보십시오. 누군가가 요소를 세어 "길이"를 결정하는 코드와 요소를 순회하여 i 번째 요소에 액세스하는 코드를 작성했습니다. ). 반복자는 매우 빠를 수 있으며 루프는 빠릅니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.