[TIL] 2024-09-05 javascript 객체 배열 랜덤 정렬

H Kim·2024년 9월 5일
0

TIL

목록 보기
68/69
post-thumbnail

아니...?
자바스크립트에 Array.random()이 없단 것을...? 이제야 알았다...?

백엔드에서 메뉴 정보가 idx 순서로 날아오고 있고 원래는 이걸 순서대로 뿌려주기만 하는데,
좌우스크롤을 하지 않는 사용자에게는 상품이 1-2개 정도밖에는 보이지 않고 하루에 몇 번을 보건 매 번 똑같은 아이템이 보여지니까 이것에 대한 흥미가 들지 않는다는 의견이 있어 이 섹션을 랜덤으로 배열하기로 했다.
백엔드 리소스는 언제나 부족하니까 프론트인 내가 담당하게 되었는데...
난 당연히 뭔가... random()하고 배열 랜덤으로 해버린다음에 다시 재할당~! 하면 끝날 줄 알았더니!!!
아니었다;;;

알고보니... 자바스크립트에는 랜덤배열 메소드가 따로 존재하지 않는다고 한다...
여러가지 방법을 찾아보았는데 대부분 배열의 원소들이 객체가 아닌 숫자로 이루어져 있어서 정확히 복붙해다가 내 상황에 들어맞게 만들 수는 없었다.
그래도 개중에 이 포스팅이 많은 도움을 주었다.

Javascript - 배열의 요소를 무작위로 섞는 방법 [array, shuffle]


나는 [{ idx: 123, productName: 'strawberry', price: 3000 }, { idx: 124, productName: 'mango', price: 5000 }, { idx: 125, productName: 'melon', price: 9000 }, { idx: 126, productName: 'apple', price: 1000 }, { idx: 127, productName: 'orange', price: 3000 }] 와 같은 배열을 랜덤배열 시켜야 했다.

최종 코드는 아래와 같다.

  const revisedThemeGoodsData = useMemo(() => {
    // 상품 데이터만 따로 변수에 할당(depth가 좀 깊어서)
    const originProduct = data?.originProductInfo;
    // 랜덤 배열할 새로운 배열 생성 및 초기화
    const randomProductArr: Menu[] = [];
    // 상품 데이터 undefined 예외 처리
    if (originProduct) {
      // 상품 데이터에서 메뉴 빼 오기
      const { menus } = originProduct[0];
      // 메뉴 데이터 undefined 예외 처리
      if (menus) {
        // 객체 형태로는 랜덤 배열이 어려워서 idx만 걸러서 새로운 배열 만듦
        const menusIndex = menus.map((el) => el.idx);
        // 메뉴인덱스 배열에서 뒤에서부터 차례로 랜덤으로 생성한 인덱스와 자리를 바꾸는 반복문
        // 새로운 배열에 넣으면 중복된 값이 계속 들어가서 반드시 원래 배열을 직접 바꿔야 함
        // 원래 배열을 바꿀 경우 중복된 randomIdx가 생성돼도 바뀐 것이 또 바뀔 뿐이지만
        // 새로 생성한 배열에 값을 지정할 경우에는 중복된 값이 또 들어가 버림
        for (let idx = menusIndex.length - 1; idx > 0; idx -= 1) {
          const randomIdx = Math.floor(Math.random() * (idx + 1));
          const temp = menusIndex[idx];
          menusIndex[idx] = menusIndex[randomIdx];
          menusIndex[randomIdx] = temp;
        }
        // 랜덤으로 배열된 menusIndex배열의 값으로 원래 menus 배열에서 해당 객체를 빼서 랜덤으로 상품 정보를 나열하는 랜덤 배열에 넣기
        for (let i = 0; i < menusIndex.length; i += 1) {
          const matchProduct = menus.filter((el) => el.idx === menusIndex[i]);
          if (matchProduct) {
            randomProductArr.push(matchProduct[0]);
          }
        }
      }
      // 상품 데이터의 menus를 만든 랜덤배열로 바꿈
      originProduct[0].menus = randomProductArr;
    }
    // 여기서는 바뀐 menus의 정보가 랜덤으로 정렬된 배열값으로 들어감
    const themeGoods = [...(data?.autoThemeGoods || []), ...(data?.originProductInfo || [])];

    themeGoods.sort((current, next) => {
      const isNeedSwitch =
        themeGoodsTypePosition.indexOf(current.themeGoodsType) > themeGoodsTypePosition.indexOf(next.themeGoodsType);
      return isNeedSwitch ? 1 : -1;
    });

    return themeGoods;
  }, [data]);

ㅎ ㅏ... 너무 힘들었다...
애초에 백엔드 개발도 그지같이 되어 있어서 쓸데없이 depth 깊은데 이거 데이터를 또 바꿔치기 할려니까 머리를 엄청 싸맸네...

원래 처음에는 원래 배열을 복사해다가 뭐 거기서 삭제해 나가면서 새로운 랜덤배열을 생성하고 막 이러려고 했는데 이러면 한 스코프 안에서 반복문을 너무 많이 써야 돼서(지금이라고 안 쓰는 것은 아닙니다만...)
아무도 못 알아볼 것 같길래 다 때려치고 그냥 딱 보기에 제일 나은 걸로 했다.
아직 팀원들에게 보여주지 않아서 이대로 배포 나갈 수 있을지 아님 리팩토링이 들어갈지 모르겠군...
리팩토링이 들어간다면 다시 찾아오도록 하겠습니다...

0개의 댓글