Home > Backend Development > ๐Ÿ“š[Backend Development] increase๋ฉ”์„œ๋“œ ๋‚ด๋ถ€ for๋ฌธ ์‹คํ–‰ ๊ณผ์ • ์ƒ์„ธ ๋ถ„์„

๐Ÿ“š[Backend Development] increase๋ฉ”์„œ๋“œ ๋‚ด๋ถ€ for๋ฌธ ์‹คํ–‰ ๊ณผ์ • ์ƒ์„ธ ๋ถ„์„
Backend Ddevelopment

โ€œ๐Ÿ“š[Backend Development] increase๋ฉ”์„œ๋“œ ๋‚ด๋ถ€ for๋ฌธ ์‹คํ–‰ ๊ณผ์ • ์ƒ์„ธ ๋ถ„์„โ€

๐Ÿ“Œ CommentPath ํด๋ž˜์Šค.

package kobe.board.comment.entity;

import jakarta.persistence.Embeddable;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Getter
@ToString
@Embeddable
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class CommentPath {
	private String path;

	private static final String CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

	private static final int DEPTH_CHUNK_SIZE = 5;
	private static final int MAX_DEPTH = 5;

	// MIN_CHUNK = "00000", MAX_CHUNK = "zzzzz"
	private static final String MIN_CHUNK = String.valueOf(CHARSET.charAt(0)).repeat(DEPTH_CHUNK_SIZE);
	private static final String MAX_CHUNK = String.valueOf(CHARSET.charAt(CHARSET.length() - 1)).repeat(DEPTH_CHUNK_SIZE);

	public static CommentPath create(String path) {
		if (isDepthOverflowed(path)) {
			throw new IllegalStateException("depth overflowed");
		}

		CommentPath commentPath = new CommentPath();
		commentPath.path = path;
		return commentPath;
	}

	private static boolean isDepthOverflowed(String path) {
		return calculateDepth(path) > MAX_DEPTH;
	}

	private static int calculateDepth(String path) {
		// 25๊ฐœ์˜ ๋ฌธ์ž์—ด / 5 = 5depth
		return path.length() / DEPTH_CHUNK_SIZE;
	}

	// CommentPath ํด๋ž˜์Šค์˜ path์˜ depth๋ฅผ ๊ตฌํ•˜๋Š” ๋งค์„œ๋“œ
	public int getDepth() {
		return calculateDepth(path);
	}

	// root์ธ์ง€ ํ™•์ธํ•˜๋Š” ๋งค์„œ๋“œ
	public boolean isRoot() {
		// ํ˜„์žฌ์˜ depth๊ฐ€ 1์ธ์ง€ ํ™•์ธํ•ด์ฃผ๋ฉด ๋จ
		return calculateDepth(path) == 1;
	}

	// ํ˜„์žฌ path์˜ parentPath๋ฅผ ๋ฐ˜ํ™˜ํ•ด์ฃผ๋Š” ๋งค์„œ๋“œ
	public String getParentPath() {
		// ๋ 5์ž๋ฆฌ๋งŒ ์ž˜๋ผ๋‚ด๋ฉด ๋จ
		return path.substring(0, path.length() - DEPTH_CHUNK_SIZE);
	}

	// ํ˜„์žฌ path์˜ ํ•˜์œ„ ๋Œ“๊ธ€์˜ path์„ ๋งŒ๋“œ๋Š” ๋งค์„œ๋“œ
	public CommentPath createChildCommentPath(String descendantsTopPath) {
		if (descendantsTopPath == null) {
			return CommentPath.create(path + MIN_CHUNK);
		}
		String childrenTopPath = findChildrenTopPath(descendantsTopPath);
		return CommentPath.create(increase(childrenTopPath));
	}

	// 00a0z0000200000 <- descendantsTopPath
	private String findChildrenTopPath(String descendantsTopPath) {
		return descendantsTopPath.substring(0, (getDepth() + 1) * DEPTH_CHUNK_SIZE);
	}

	private String increase(String path) {
		// path์—์„œ ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰ 5์ž๋ฆฌ๋ฅผ ์ž๋ฅธ ๊ฒƒ
		String lastChunk = path.substring(path.length() - DEPTH_CHUNK_SIZE);

		if (isChunkOverflowed(lastChunk)) {
			throw new IllegalStateException("chunk overflowed");
		}

		// Character set์˜ ๊ธธ์ด
		int charsetLength = CHARSET.length();

		// lastChunk๋ฅผ 10์ง„์ˆ˜๋กœ ๋จผ์ € ๋ณ€ํ™˜ํ•˜๊ธฐ ์œ„ํ•œ ๊ฐ’์„ ์ €์žฅ
		int value = 0;

		for (char character : lastChunk.toCharArray()) {
			value = value * charsetLength + CHARSET.indexOf(character);
			System.out.println("value ====> " + value);
			System.out.println("CHARSET.indexOf ====> " +  CHARSET.indexOf(character));
		}

		value = value + 1;

		String result = "";

		for (int i = 0; i < DEPTH_CHUNK_SIZE; i++) {
			result = CHARSET.charAt(value % charsetLength) + result;
			value /= charsetLength;
		}

		return path.substring(0, path.length() - DEPTH_CHUNK_SIZE) + result;
	}

	private boolean isChunkOverflowed(String lastChunk) {
		return MAX_CHUNK.equals(lastChunk);
	}
}

๐Ÿ“Œ for ๋ฌธ ์‹คํ–‰ ๊ณผ์ • ์ƒ์„ธ ๋ถ„์„

  • ํ•ด๋‹น for ansdms ์ฃผ์–ด์ง„ value(10์ง„์ˆ˜)๋ฅผ CHARSET(62์ง„์ˆ˜)๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๋ฌธ์ž์—ด(result)์„ ์ƒ์„ฑํ•˜๋Š” ๊ณผ์ •์ž…๋‹ˆ๋‹ค.

1๏ธโƒฃ for ๋ฌธ ์ฝ”๋“œ

for (int i = 0; i < DEPTH_CHUNK_SIZE; i++) {
    result = CHARSET.charAt(value % charsetLength) + result;
    value /= charsetLength;
}

โœ… ์ฃผ์š” ๊ฐœ๋…

  • value % charsetLength โžž 62์ง„์ˆ˜์—์„œ ๊ฐ€์žฅ ๋‚ฎ์€ ์ž๋ฆฌ์ˆ˜(์˜ค๋ฅธ์ชฝ ๋)๋ฅผ ๊ตฌํ•จ
  • CHARSET.charAt(value % charsetLenht) โžž CHARSET์—์„œ ํ•ด๋‹น ์ธ๋ฑ์Šค์˜ ๋ฌธ์ž(0~9, A~Z, a~z)๋ฅผ ๊ฐ€์ ธ์˜ด
  • value /= charsetLength โžž ๋‹ค์Œ ์ž๋ฆฌ์ˆ˜๋ฅผ ๊ณ„์‚ฐํ•˜๊ธฐ ์œ„ํ•ด value๋ฅผ 62๋กœ ๋‚˜๋ˆ”
  • result = CHARSET.charAt(value % charsetLenght) + resultl โžž ๋ฌธ์ž์—ด์˜ ์•ž์— ์ถ”๊ฐ€ํ•˜์—ฌ ๋ณ€ํ™˜ ๊ฒฐ๊ณผ๋ฅผ ๋งŒ๋“ ๋‹ค

2๏ธโƒฃ for ๋ฌธ ์‹คํ–‰ ๊ณผ์ • ๋‹จ๊ณ„๋ณ„ ๋ถ„์„

๐Ÿ“Œ ์˜ˆ์ œ 1: value = 1, charsetLenght = 62, DEPTH_CHUNK_SIZE = 5

โœ… ์ดˆ๊ธฐ ๊ฐ’

value = 1;
resutl = "";

โœ… ๋ฐ˜๋ณต ๊ณผ์ •

๋ฐ˜๋ณต value value % 62 CHARSET.charAt(value % 62) result value /= 62
i=0 1 1 โ€˜1โ€™ โ€œ1โ€ 0
i=1 0 0 โ€˜0โ€™ โ€œ01โ€ 0
i=2 0 0 โ€˜0โ€™ โ€œ001โ€ 0
i=3 0 0 โ€˜0โ€™ โ€œ0001โ€ 0
i=4 0 0 โ€˜0โ€™ โ€œ00001โ€ 0

โœ… ์ตœ์ข… ๊ฒฐ๊ณผ

result = "00001";

๐Ÿ“Œ ์˜ˆ์ œ 2: value = 62

โœ… ์ดˆ๊ธฐ ๊ฐ’

value = 62;
resutl = "";

โœ… ๋ฐ˜๋ณต ๊ณผ์ •

๋ฐ˜๋ณต value value % 62 CHARSET.charAt(value % 62) result value /= 62
i=0 62 0 โ€˜0โ€™ โ€œ0โ€ 1
i=1 1 1 โ€˜1โ€™ โ€œ10โ€ 0
i=2 0 0 โ€˜0โ€™ โ€œ010โ€ 0
i=3 0 0 โ€˜0โ€™ โ€œ0010โ€ 0
i=4 0 0 โ€˜0โ€™ โ€œ00010โ€ 0

โœ… ์ตœ์ข… ๊ฒฐ๊ณผ

result = "00010";

๐Ÿ“Œ ์˜ˆ์ œ 3: value = 3843

โœ… ์ดˆ๊ธฐ ๊ฐ’

value = 3843;
resutl = "";

โœ… ๋ฐ˜๋ณต ๊ณผ์ •

๋ฐ˜๋ณต value value % 62 CHARSET.charAt(value % 62) result value /= 62
i=0 3843 61 โ€˜zโ€™ โ€œzโ€ 61
i=1 61 61 โ€˜zโ€™ โ€œzzโ€ 0
i=2 0 0 โ€˜0โ€™ โ€œ0zzโ€ 0
i=3 0 0 โ€˜0โ€™ โ€œ00zzโ€ 0
i=4 0 0 โ€˜0โ€™ โ€œ000zzโ€ 0

โœ… ์ตœ์ข… ๊ฒฐ๊ณผ

result = "000zz";

๐Ÿ“Œ ํ•ต์‹ฌ ์ •๋ฆฌ

๐Ÿ“ for ๋ฌธ์ด ํ•˜๋Š” ์ผ

    1. value(10์ง„์ˆ˜)๋ฅผ 62์ง„์ˆ˜ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค.
    1. CHARSET.charAt(value % 62)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ€์žฅ ๋‚ฎ์€ ์ž๋ฆฌ์ˆ˜๋ถ€ํ„ฐ ๋ณ€ํ™˜ํ•œ๋‹ค.
  • 3.๋ณ€ํ™˜๋œ ๋ฌธ์ž๋ฅผ result ์•ž์— ์ถ”๊ฐ€(+ result)
    1. value /= 62 ํ•˜์—ฌ ๋‹ค์Œ ์ž๋ฆฌ์ˆ˜๋ฅผ ๊ณ„์‚ฐ.
    1. ์ตœ์ข…์ ์œผ๋กœ DEPTH_CHUNK_SIZE(5)๋งŒํผ ๋ฐ˜๋ณตํ•˜์—ฌ 5์ž๋ฆฌ ๋ฌธ์ž์—ด์„ ๋งŒ๋“ ๋‹ค.

๐Ÿ“Œ ๊ฒฐ๋ก 

  • value์˜ ์ž‘์€ ์ž๋ฆฌ์ˆ˜๋ถ€ํ„ฐ ๋ณ€ํ™˜ํ•˜์—ฌ ๋ฌธ์ž์—ด์„ ๊ตฌ์„ฑํ•œ๋‹ค.
  • 62์ง„๋ฒ• ๋ณ€ํ™˜์›๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋Œ“๊ธ€์˜ path๋ฅผ ์ฆ๊ฐ€์‹œํ‚ค๋Š” ๋ฐ ํ™œ์šฉํ•œ๋‹ค.