각 언어별 sort에 대한 정리

정렬 방식 정리하기

sort는 자주 사용하면서도 나중에 사용 할때마다 조금씩 헷갈리는 부분이라 정리해둘까 한다.

JAVA

자바에 여러가지 방식이 있다.

  • Comparator
  • Comparable
  • Lambda

Comparator

Comparator 방식으로 내가 자주 사용하는 방식이다. 이 방식을 사용하면 개인적으로 내가 원하는 정렬 방식으로 변경하기도 간편하다고 생각하기 때문이다.

아래 코드를 보면

1차원 배열

import java.util.Arrays;
import java.util.Comparator;

int N = 10;
int[] arr = new int[N];

Arrays.sort(arr, new Comparator<Integer>) {
    @Override
    public int compare(Object o1, Object o2) {
        return o1 - o2;     // 오름차순
    }
}

2차원 배열

import java.util.Arrays;
import java.util.Comparator;

int N = 10;
int[][] arr = new int[N][N];

Arrays.sort(arr, new Comparator<int[]>) {
    @Override
    public int compare(int[] o1, int[] o2) {
        if(o1[0] == o2[0]) {
            return o1[1] - o2[1];   // 오름차순
        } else {
            return o1[0] - o2[0];
        }
    }
}

위 소스는 기본적으로 오름차순으로 되어 있고, 내림차순으로 정렬을 원한다면 반대로 리턴해준다.

    return o2 - o1;     // 내림차순

기본적으로 리턴의 값이 음수이면 오름차순, 양수이면 내림차순으로 정렬이 된다고 생각하면 이해하기 쉽다.

Comparable

Comparable 인터페이스에는 comepareTo() 추상메서드 하나만 존재한다.

주어진 객체보다 작으면 음수, 같으면0, 크면 양수를 리턴한다.

public class NameCard implements Comparable<NameCard> {
    public String name;
    public int age;

    public NameCard(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public int compareTo(NameCard o) {
        if(this.age < o.age) {
            return -1;
        } else (this.age > o.age) {
            return 1;
        } else
            return 0;
    }
}

public class Main {
    public static void main(String[] args) {
        List<NameCard> list = new ArrayList<>();
        list.add(new NameCard("김자바", 9));
        list.add(new NameCard("박파이썬", 10));
        list.add(new NameCard("신씨", 1));
        list.add(new NameCard("양자스", 7));

        Collections.sort(list);

        for(NameCard n : list) {
            System.out.println(n.name + " " + n.age);
        }
    }
}

Result :
신씨 1
양자스 7
김자바 9
박파이썬 10

Lambda

람다 방식으로도 간결하게 표현하여 정렬할 수 있다.

1차원 배열

import java.util.Arrays;

int N = 10;
int[] arr = new int[N];

Arrays.sort(arrays, (o1, o2) -> o1 - o2);

2차원 배열

import java.util.Arrays;

int N = 10;
int[] arr = new int[N];

Arrays.sort(arrays, (o1, o2) -> o1[0] == o2[0] ? o1[1] - o2[1] : o1[0] - o2[0]);

같은 방식이지만 사용하면서 더 편한 방법으로 사용하면 될 것 같다.


JavaScript

자바스크립트 방식은 최근에 웹 프론트 개발자로 이직하기 위해서 알고리즘을 하면서 사용해 보았다.

let arr = [];

arr.sort([compareFunction]);

파라미터
compareFunction

정렬 순서를 정의하는 함수
이 값이 생략되면, 배열의 element들은 문자열로 취급되어 유니코드 값 순서대로 정렬된다.
이 함수는 두 개의 배열 element를 파라미터로 입력 받는다.
이 함수가 a, b 두개의 element를 파라미터로 입력받을 경우,
이 함수가 리턴하는 값이 0보다 작을 경우, a가 b보다 앞에 오도록 정렬하고,
이 함수가 리턴하는 값이 0보다 클 경우, b가 a보다 앞에 오도록 정렬한다.
만약 0을 리턴하면, a와 b의 순서를 변경하지 않는다.

리턴값
compareFunction 규칙에 따라서 정렬된 배열을 리턴한다.
이때, 원본 배열인 arr가 정렬이 되고, 리턴하는 값 또한 원본 배열인 arr을 가리키고 있다.

const arr1 = [2, 1, 3];
const arr2 = ['banana', 'apple', 'orange'];

arr1.sort();
document.writeln(arr1 + '<br>');

arr2.sort();
document.writeln(arr2 + '<br>');

Result :
1, 2, 3
apple,banana,orange

const arr = [2, 1, 3, 10];

arr.sort(function(a, b) {
    return a - b;
});
document.writeln(arr + '<br>');

Result :
1, 2, 3, 10

이 경우에도 a - b가 음수면 오름차순, 양수면 내림차순이 된다.

또한 객체로 구분하여 정렬하는 방법도 생각해 볼 수 있다.

const arr = [
    {name: 'banana', price: 3000},
    {name: 'apple', price: 1000},
    {name: 'orange', price: 500}
];

arr.sort(function(a, b) {
    return a.price - b.price;
});
document.writeln(JSON.stringify(arr[0]) + '<br>');

Result
{name: ‘orange’, price: 500}, {name: ‘apple’, price: 1000}, {name: ‘banana’, price: 3000},

틀리거나 이상한 내용이 있다면 알려주세요!

2885.초콜릿 식사 - 백준온라인

백준 알고리즘 문제 풀이

해당 문제는 탐욕(greedy) 알고리즘을 사용하여 문제를 해결 했습니다.

링크 : image


2885.초콜릿 식사

학교 근처 편의점에 새 초콜릿이 들어왔다. 이 초콜릿은 막대 모양이고, 각 막대는 정사각형 N개로 이루어져 있다. 초콜릿의 크기(정사각형의 개수)는 항상 2의 제곱 형태이다. 즉, 1, 2, 4, 8, 16, …개의 정사각형으로 이루어져 있다.

상근이는 점심식사로 초콜릿을 먹는다. 이때, 적어도 K개 정사각형을 먹어야 남은 수업을 졸지 않고 버틸 수 있다. 상근이의 친구 선영이도 초콜릿을 좋아한다. 선영이는 초콜릿은 돈을 주고 사기 아깝다고 생각하기 때문에, 상근이가 주는 초콜릿만 먹는다.

상근이는 막대 초콜릿를 하나 산 다음에, 정확하게 K개 정사각형이 되도록 초콜릿을 쪼갠다. K개는 자신이 먹고 남는 것은 선영이에게 준다.

막대 초콜릿은 나누기 조금 어렵게 되어 있어서, 항상 가운데로만 쪼개진다. 즉, 정사각형이 D개 있는 막대는 D/2개 막대 두 조각으로 쪼개진다.

K개 정사각형을 만들기 위해서, 최소 몇 번 초콜릿을 쪼개야 하는지와 사야하는 가장 작은 초콜릿의 크기를 구하는 프로그램을 작성하시오. 상근이는 초콜릿을 하나만 살 수 있다. 꼭 한 조각이 K개일 필요는 없고, 여러 조각에 있는 정사각형을 합쳤을 때 K개이면 된다.

입력(Input)

첫째 줄에 K가 주어진다. (1 ≤ K ≤ 1,000,000)

출력(Output)

첫째 줄에는 상근이가 구매해야하는 가장 작은 초콜릿의 크기와 최소 몇 번 쪼개야 하는지를 출력한다.


1. 문제 풀이

그리디 알고리즘을 이용하는 문제를 해결해보았다.

초콜릿이 나누어지는 경우가 무조건 D = D / 2로 반으로만 나눌 수 있고, 초콜릿의 크기는 2의 제곱 형태이다.

초콜릿을 반으로 나누면 나누어진 초콜릿 중 반 쪽은 그 상태로 남고, 다른 반 쪽으로 다시 나누기를 시도하여 이 초콜릿의 누적 개수가 K가 되면 되는 문제이다.

계속 나누다보면 결국에는 2 = 1 + 1이 될 것이니, 필요한 K의 갯수보다 한 제곱 더 큰 초콜릿을 사면 되는 것이다.

K = 6
\(2^2 = 4\) \(2^3 = 8\) 이므로 4 < K < 8
8의 초콜릿을 구매

위의 방식대로 초콜릿을 구매하고, 남은 개수는 다른 반쪽을 나누어가며 채워가면 된다.

8을 나누어 4개 | 4개
반쪽인 4개를 K에서 제외하고, 다른 반쪽을 나눈다.
K(6) - 4 = 2
4을 나누어 2개 | 2개
반쪽인 2개를 K에서 제외하면 정량이 된다.
K(2) - 2 = 0

이것을 코드로 표현하겠습니다.


import java.util.Scanner;

public class ChocolateEat_2885 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int K = sc.nextInt();
        int D = 0;
        int i = 0;
        
        while(D < K) {
            D = (int)Math.pow(2, i);  // 1, 2, 4, 8, 16...
            i++;
        }

        int size = D, cnt = 0;
        while(K > 0) {
            if(K >= D) {
                K -= D;
            } else {
                D /= 2;
                cnt++;
            }
        }

        System.out.println(size + " " + cnt);
    }
}

아이디어나 생각 기록 포스트 시작

아이디어나 생각 기록 포스트 시작

아이디어나 생각 기록, 그 첫번째 포스트!!

일상 기록하는 디렉토리를 만들고 나니 내 생각이나 아이디어가 떠오르면 작성할 수 있는 페이지가 있다면 좋을 것 같다는 생각이 들었다.

평소에 이런 저런 생각을 많이 하는 나는 좋은 생각이 떠오르다가도 메모장에 적던 습관이 부족해서 금방 잊곤 했는데, 그런 생각을 간단하게 적을 수 있다면 좋을 것 같아서 따로 분리하게 되었다.

이 디렉토리가 가득 찰 수 있다면 좋겠는걸..

18185.라면 사기(small) - 백준온라인

백준 알고리즘 문제 풀이

해당 문제는 탐욕(greedy) 문제로 현재 수행 하는것이 최선임을 정의하여 푸는 문제입니다.

그리디도 중요하지만 예외 처리가 중요한 부분이다.

링크 : image


18185.라면 사기(small)

라면매니아 교준이네 집 주변에는 N개의 라면 공장이 있다. 각 공장은 1번부터 N번까지 차례대로 번호가 부여되어 있다. 교준이는 i번 공장에서 정확하게 Ai개의 라면을 구매하고자 한다(1 ≤ i ≤ N).

교준이는 아래의 세 가지 방법으로 라면을 구매할 수 있다.

i번 공장에서 라면을 하나 구매한다(1 ≤ i ≤ N). 이 경우 비용은 3원이 든다. i번 공장과 (i+1)번 공장에서 각각 라면을 하나씩 구매한다(1 ≤ i ≤ N-1). 이 경우 비용은 5원이 든다. i번 공장과 (i+1)번 공장, (i+2)번 공장에서 각각 라면을 하나씩 구매한다(1 ≤ i ≤ N-2). 이 경우 비용은 7원이 든다. 최소의 비용으로 라면을 구매하고자 할 때, 교준이가 필요한 금액을 출력하는 프로그램을 작성하시오.

입력(Input)

첫째 줄에 센서의 개수 N(1 ≤ N ≤ 10,000), 둘째 줄에 집중국의 개수 K(1 ≤ K ≤ 1000)가 주어진다. 셋째 줄에는 N개의 센서의 좌표가 한 개의 정수로 N개 주어진다. 각 좌표 사이에는 빈 칸이 하나 있으며, 좌표의 절댓값은 1,000,000 이하이다.

출력(Output)

첫째 줄에 문제에서 설명한 최대 K개의 집중국의 수신 가능 영역의 길이의 합의 최솟값을 출력한다.


1. 문제 풀이

그리디 알고리즘을 이용하는 문제인데, 구매 가능한 행동이 3가지이다.
그리고, i 번째 공장 i + 1 번째 공장, i + 2 번째 공장의 라면 개수에 따라서 구매 방식을 다르게 접근해야 한다.

하나의 공장에서 3원으로 구매하는것 보다 두 개의 공장에서 5원으로 구매하는것이,
세 개의 공장에서 7원으로 구매하는것이 효율적이라는것은 누구나 알 수 있다.

그래서 처음에는 현 위치 i에서 i + 1 번째와 i + 2 번째 공장과의 살 수 있는 최대한으로 묶어서 구매하는 방식으로 문제를 풀어 봤다.

  • 3개씩 묶어서 구매

    1 2 3
    최소값인 1개씩 구매하여
    0 1 2
    을 만들면, 현 위치에서 구매 한 금액은 최소 값 1 * 7 = 7원

  • 2개씩 묶어서 구매

    4 2 0 3
    최소 값인 2개씩 구매하여
    2 0 0 3
    0 0 0 3
    2 * 5 + 2 * 3 = 16원

그러나 위의 방식대로 접근하니 더 효율적으로 구매하지 못하는 예외 경우가 있었다.
바로 i + 1 번째가 i + 2 번째보다 큰 경우인데, 아래를 살펴보면

2 3 2 1
인근 최소값인 2개씩 구매하여
0 1 0 1
0 0 0 1
0 0 0 0
(2 * 7) + (1 * 3) + (1 * 3) = 20원

위와 같이 20원이 나오지만, 아래와 같이 앞의 2개씩 묶어서 뒤의 수와 일치 시켜주면

2 3 2 1
1 2 2 1
0 2 2 1
0 1 1 1
0 0 0 0
(1 * 5) + (1 * 3) + (1 * 5) + (1 * 7) = 19원

19원으로 더 싸게 구매가 가능한 것이다.

이는 i + 1 번째 값이 i + 2 번째 값보다 클 경우인데, 이 때에는 i 번째의 값과 [i + 1] - [i + 2] 의 값의 최소값 만큼 앞의 두개를 묶어서 사면 다음 구매에 더 싸게 구매가 가능하게 된다.

따라서 아래의 두 가지 방식으로 분기하여 그리디 방식으로 최대한 이익을 내서 구매를 한다면,

  1. [i + 1] 공장의 라면 > [i + 2] 공장의 라면
    • [i], [i + 1] - [i + 2] 중의 최소값으로 선 구매 (2묶음)
    • [i], [i + 1], [i + 2] 중의 최소값으로 구매 (3묶음)
  2. [i + 1] 공장의 라면 < [i + 2] 공장의 라면
    • [i], [i + 1], [i + 2] 중의 최소값으로 선 구매 (3묶음)
    • [i], [i + 1] 중의 최소값으로 구매 (2묶음)

    • [i] 의 남은 개수 구매

가장 최소의 금액으로 구매 할 수 있는 금액이 나오게 된다.

이것을 코드로 표현하겠습니다.


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Ramyeon_18185 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int N = Integer.parseInt(st.nextToken());
        int factory[] = new int[N + 2];

        st = new StringTokenizer(br.readLine());
        for (int i = 0; i < N; i++) {
            factory[i] = Integer.parseInt(st.nextToken());
        }

        int answer = 0;
        for(int i = 0; i < N; i++) {
            if(factory[i] > 0) {
                // i + 1, i + 2 번 가게의 라면 유무를 확인
                // 현재 살 수 있는 가장 많은 라면을 산다.
                int min = 0;

                if(factory[i + 1] > factory[i + 2]) {
                    // i + 1의 수가 i + 2의 수보다 크면,
                    // 맨 앞의 두개를 묶어서 먼저 사고, 세 개를 묶어서 사는게 싸다.
                    // 이 때, [i] > [i+1] - [i+2] 의 값을 비교하여 최소값으로 구매
                    min = Math.min(factory[i], factory[i + 1] - factory[i + 2]);
                    answer += min * 5;
                    factory[i] -= min;
                    factory[i + 1] -= min;

                    min = Math.min(factory[i], Math.min(factory[i + 1], factory[i + 2]));
                    answer += min * 7;
                    factory[i] -= min;
                    factory[i + 1] -= min;
                    factory[i + 2] -= min;
                } else {    // 반대는 세개 묶어 사고, 두개 묶어 사는게 싸다.
                    min = Math.min(factory[i], Math.min(factory[i + 1], factory[i + 2]));
                    answer += min * 7;
                    factory[i] -= min;
                    factory[i + 1] -= min;
                    factory[i + 2] -= min;

                    min = Math.min(factory[i], factory[i + 1]);
                    answer += min * 5;
                    factory[i] -= min;
                    factory[i + 1] -= min;
                }
                answer += factory[i] * 3;
                factory[i] = 0;
            }
        }

        System.out.println(answer);
    }
}

일상 기록 - 삼겹살 먹부림

일상 기록

오늘 오랜만에 집 근처에 있는 삼겹살집에 갔다. 퇴근 후 평소와는 다른 방향으로 걸어가면서 삼겹살이 먹고 싶다던 승토리와 함께 돼지고기 뿌시러 갔다.

해바라기집이라는 이곳은 이 집에 온지 얼마 안 지나서 방문하고 이번이 두 번째 방문이다. image

돼지 반마리를 시켰는데, 위에 사진 처럼 두꺼운 삼겹살과 항정살, 갈비살, 목살 등이 500g 나오는데 우리 둘이서는 이정도가 딱 정당히 배부르고 좋은 것 같다.

최근에 감기 기운이 있어서 목도 칼칼하니 별로 좋지 않았는데 기름진 고기를 먹으며 힐링했던 시간

2212.센서 - 백준온라인

백준 알고리즘 문제 풀이

해당 문제는 탐욕(greedy) 문제로 현재 수행 하는것이 최선임을 정의하여 풀어보았습니다.

링크 : image


2212. 센서

한국도로공사는 고속도로의 유비쿼터스화를 위해 고속도로 위에 N개의 센서를 설치하였다. 문제는 이 센서들이 수집한 자료들을 모으고 분석할 몇 개의 집중국을 세우는 일인데, 예산상의 문제로, 고속도로 위에 최대 K개의 집중국을 세울 수 있다고 한다.

각 집중국은 센서의 수신 가능 영역을 조절할 수 있다. 집중국의 수신 가능 영역은 고속도로 상에서 연결된 구간으로 나타나게 된다. N개의 센서가 적어도 하나의 집중국과는 통신이 가능해야 하며, 집중국의 유지비 문제로 인해 각 집중국의 수신 가능 영역의 길이의 합을 최소화해야 한다.

편의를 위해 고속도로는 평면상의 직선이라고 가정하고, 센서들은 이 직선 위의 한 기점인 원점으로부터의 정수 거리의 위치에 놓여 있다고 하자. 따라서, 각 센서의 좌표는 정수 하나로 표현된다. 이 상황에서 각 집중국의 수신 가능영역의 거리의 합의 최솟값을 구하는 프로그램을 작성하시오. 단, 집중국의 수신 가능영역의 길이는 0 이상이며 모든 센서의 좌표가 다를 필요는 없다.

입력(Input)

첫째 줄에 센서의 개수 N(1 ≤ N ≤ 10,000), 둘째 줄에 집중국의 개수 K(1 ≤ K ≤ 1000)가 주어진다. 셋째 줄에는 N개의 센서의 좌표가 한 개의 정수로 N개 주어진다. 각 좌표 사이에는 빈 칸이 하나 있으며, 좌표의 절댓값은 1,000,000 이하이다.

출력(Output)

첫째 줄에 문제에서 설명한 최대 K개의 집중국의 수신 가능 영역의 길이의 합의 최솟값을 출력한다.


1. 문제 풀이

이것을 코드로 표현하겠습니다.


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Sensor_2212 {
    static int[] sensors;
    static int[] diff;
    public static  void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int N = Integer.parseInt(st.nextToken());
        st = new StringTokenizer(br.readLine());
        int K = Integer.parseInt(st.nextToken());

        sensors = new int[N];
        diff = new int[N - 1];
        st = new StringTokenizer(br.readLine());
        for(int i = 0; i < N; i++) {
            sensors[i] = Integer.parseInt(st.nextToken());
        }

        if(K >= N) System.out.println("0");
        else {
            Arrays.sort(sensors);

            for(int i = 0; i < N - 1; i++) {
                diff[i] = sensors[i + 1] - sensors[i];
            }

            Arrays.sort(diff);

            int answer = 0;

            for(int i = 0; i < N - K; i++) {
                answer += diff[i];
            }

            System.out.println(answer);
        }
    }
}

일상 기록 - 깃 저장소 변경

일상 기록 - 깃 저장소 변경

깃 저장소 변경하면서 잠깐 쉬는 타임에 끄적여보는 일상 기록

기존 학부시절부터 사용했던 깃 저장소(git_storage_gahu)에서 했었던 프로젝트와 공부 했던 기록들을 정리해서 새로운 깃 저장소(git_storage_gahusb)로 변경하였다.

기존의 깃이 공부하면서 썻던 내용들이라… 정리도 되어 있지 않았고 그래서 뭔가 지저분하게 되어 있는데 어디서부터 손을 대야 할지 감이 잡히지 않았다.

때문에 새로운 저장소를 만들고, github io를 이용하여 나의 블로그도 작성하면서 기존 프로젝트들의 내용 정리와 블로그 정리 두가지를 같이 하면서 옮기게 되었다.

블로그 작업 준비도 하면서 기존 프로젝트들을 옮기고 정리한다는게 쉬운 일은 아니지만 지금 목표로 하고 있는 일이 있기 때문에 시작을 할 수 있었던것 같고, 무엇보다도 새로 산 Macbook M1 Max를 잘 활용해 볼 수 있는 기회가 되지 않을까 생각하면서 작업하고 있다.

일상 기록 첫 번째 이야기

일상 기록, 그 첫번째 포스트!!

깃 블로그를 만들면서 앞으로 써 내려갈 일상 디렉토리의 첫 번째 포스트를 작성해 봅니다.

어려서부터 내 생각을 정리하거나 메모를 할 때에는 간단히 들고 다니는 메모장이나 노트에 많이 끄적여 봤는데,

이처럼 누구나 볼 수 있는 페이지에 나의 일상을 기록하고 내 생각을 정리하는 포스트를 만든다는게 너무 어색하기만 하다 :)

평소에 글을 쓰는걸 별로 좋아하지 않았기 때문에 글을 작성하는데에도 많은 시간이 소요되고 내용도 알차지는 못하겠지만, 점점 나의 글을 쓰면서 어제보다 발전해가는 모습을 볼 수 있지 않을까?!

때문에 일상 포스트를 꼭 해보고 싶었다.

깃 블로그 일상 포스트 시작합니다.

Web-first-test-page

Web-first-test-page

Version 9 is the most complete version of Hydejack yet. Modernized design, big headlines, and big new features.

Version 9 is the most complete version of Hydejack yet.

Modernized design, big headlines, big new features: Built-In Search, Sticky Table of Contents, and Auto-Hiding Navbar. That and more is Hydejack 9.

Linking in Style

Ever since the introduction of Dark Mode, link styles have been a bit of an issue. Specifically, finding an accent color that worked on both light and dark backgrounds was the problem. With Hydejack 9, the link style has been revamped so that legibility is no longer tied to the choice of accent_color, giving you much more freedom in creating a unique design flavor for your site.

Ready for the Big Screen

The theme on which Hydejack is based was designed for a different era of the web. Hydejack has inherited many of its limitations, but over time I’ve made adjustments, such as centering the content column for better reading ergonomics.

With version 9, Hydejack takes full advantage of large displays. Whether it’s design indulgences such as oversized headlines, or quality of life improvements such as a floating table of contents, Hydejack now finds use for all that extra screen real estate1.

What’s in the Cards?

Hydejack 9 now lets you use content cards for both projects and posts. The cards have been redesigned with a new hover style and drop shadows and they retain their unique transition-to-next-page animations, which now also work on the blog layout. The new grid layout lets you do that.

Good images are key to making the most out of content cards. For that reason, a chapter on images has been added to the documentation.

Hydejack now has Built-In Search. It even works offline. I’ve been prototyping many approaches and eventually settled on a fully client-side, off-the-main thread solution that perfectly fits the use case of personal sites and shows surprisingly good results2.

The new search UI is custom made for Hydejack and shows beautiful previews of your posts and pages, right on top of your regular content.

Together with the Auto-Hiding Navbar, your entire content library is now only a couple of keystrokes away.

Auto-Hiding Navbar

A navbar that’s there when you need it, and disappears when you don’t. Simple as that.

Sticky Table of Contents

Already a staple on so many sites on the web, this pattern is now also available in Hydejack. What’s unique about it is that it simply picks up the table of contents already created by kramdown’s {:toc} tag and transparently upgrades it to a fully dynamic version.

…and much more

Other noteworthy changes include:

  • Support for Jekyll 4
  • Choice between MathJax and KaTeX for math rendering
  • Use of jekyll-include-cache for drastically improved page building speeds
  • New variables configuration file — adjust content width, sidebar width, font size, etc…
  • …and the option to disable grouping projects by year.

Read the the CHANGELOG for the full scope of features and improvements made in Hydejack 9. Maybe just glance at it to confirm that it is indeed a pretty long list.

Even More to Come

New features for 9.1 are already lined up. Code block headers and code line highlights for even better technical blogging, as well as download buttons on the resume page for PDF, vCard, and Resume JSON are just around the corner.

Get It Now

The Free Version of Hydejack is now availabe on RubyGems and for the first time also on GitHub Packages. The source code is available on GitHub as always.

The PRO Version is scheduled to release on July 7th on Gumroad. Pre-Orders are open now:

  1. If you are a fan of the old two-column layout, or don’t like modern design tropes such as mega headlines, Hydejack lets you revert these changes on a case-by-case basis via configuration options. ↩︎

  2. Search was mainly tested for English and German. Please let me know about issues in other languages. While I’ve tried to find a multi-language solution, most showed drastically worse results for the English base case. If you’re technically inclined, you can adopt the code located in _includes/js/search-worker.js to your needs. ↩︎

Pagination