Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

274 - Integers Comparator #3601

Open
akcyp opened this issue Sep 28, 2021 · 0 comments
Open

274 - Integers Comparator #3601

akcyp opened this issue Sep 28, 2021 · 0 comments
Labels
274 answer Share answers/solutions to a question en in English

Comments

@akcyp
Copy link

akcyp commented Sep 28, 2021

274 - Integers Comparator

Hi, I wanted to make the simplest solution that will be understandable by everyone. Thats why each helper function describes what it should return in every possible case. There are 3 main steps to solve this problem:

  • checking if the numbers have the same signs
  • splitting number into digits
  • checking which array of digits is longer
  • if both arrays have the same length -> compare the digits one by one

Hope you will enjoy! 😄

Solution

Code

enum Comparison {
  Greater,
  Equal,
  Lower,
}

type DigitMap = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
type Digit = DigitMap[number]; // 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
type SDigit = NumberToString<Digit> // "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"

type NumberToString<T extends number> = `${T}`;
// NumberToString<123> => "123"

type IfNegative<T extends string, B, C> = T extends `-${number}` ? B : C;
// IfNegative<"-123", true, false> => true

type Abs<T extends string> = T extends `-${infer N}` ? N : T;
// Abs<"-123"> => "123", Abs<"123"> => "123"

type NumberToArray<T extends number, R extends unknown[] = []> = R['length'] extends T ? R : NumberToArray<T, [...R, unknown]>;
// NumberToArray<2> => [unknown, unknown]

type Increment<T extends number> = [...NumberToArray<T>, unknown]['length'];
// Increment<3> => 4

type NumberToSDigits<T extends string, R extends SDigit[] = []> =
  T extends SDigit ? [...R, T] :
    T extends `${infer X}${infer Y}` ?
      X extends SDigit ? NumberToSDigits<Y, [...R, X]> : never
    : never;
// NumberToDigits<"123"> => ["1", "2", "3"]

type DigitsComparator<A extends Digit, B extends Digit, R = Comparison.Equal> =
  A extends B ? R :
    Increment<A> extends Digit ? DigitsComparator<Increment<A>, B, Comparison.Lower> : Comparison.Greater;
// DigitsComparator<0, 1> => Comparison.Lower
// DigitsComparator<0, 0> => Comparison.Equal
// DigitsComparator<1, 0> => Comparison.Greater
// Checks if A comes before B with respect to DigitsMap, or vice versa
// Wanted function but only for digits

type EqualLengthComparator<
  AQ extends SDigit[],
  BQ extends SDigit[],
  I extends number = 0,
  NI extends number = Increment<I> extends number ? Increment<I> : never
> =
  AQ[I] extends BQ[I] ?
    NI extends AQ['length'] ? Comparison.Equal : EqualLengthComparator<AQ, BQ, NI> :
    DigitsComparator<DigitMap[AQ[I]], DigitMap[BQ[I]]>;
// EqualLengthComparator<["2", "3"], ["2", "3"]> => Comparison.Equal
// EqualLengthComparator<["2", "4"], ["2", "3"]> => Comparison.Greater
// EqualLengthComparator<["2", "2"], ["2", "3"]> => Comparison.Lower

type AbsoluteComparator<
  A extends string,
  B extends string,
  AQ extends SDigit[] = NumberToSDigits<A>,
  BQ extends SDigit[] = NumberToSDigits<B>,
  AQL extends number = AQ['length'],
  BQL extends number = BQ['length']
> =
  AQL extends BQL ? EqualLengthComparator<AQ, BQ> :
    AQL extends Digit ?
      BQL extends Digit ?
        DigitsComparator<AQL, BQL> : // AQL and BQL are digits
        Comparison.Lower // AQL is digit, but BQL is number
      :
      BQL extends Digit ?
        Comparison.Greater : // BQL is digit, but AQL is number
        AbsoluteComparator<NumberToString<AQL>, NumberToString<BQL>> // AQL and BQL are numbers
;

type Inverse<T extends Comparison> =
  T extends Comparison.Equal ?
    Comparison.Equal :
    T extends Comparison.Greater ? Comparison.Lower : Comparison.Greater;
// Inverse<Comparison.Equal> => Comparison.Equal
// Inverse<Comparison.Lower> => Comparison.Greater
// Inverse<Comparison.Greater> => Comparison.Lower

type NumberComparator<A extends string, B extends string> =
  A extends B ? Comparison.Equal :
    IfNegative<A,
      IfNegative<B,
        Inverse<AbsoluteComparator<Abs<A>, Abs<B>>>, // A and B are negative
        Comparison.Lower // A is negative, but B is positive
      >,
      IfNegative<B,
        Comparison.Greater, // A is positive, but B is negative
        AbsoluteComparator<A, B> // A and B are positive
      >
    >;

type Comparator<A extends number, B extends number> = NumberComparator<NumberToString<A>, NumberToString<B>>;

Test cases

/* _____________ Test Cases _____________ */
import { Equal, Expect } from '@type-challenges/utils'

type cases = [
  Expect<Equal<Comparator<5, 5>, Comparison.Equal>>,
  Expect<Equal<Comparator<5, 6>, Comparison.Lower>>,
  Expect<Equal<Comparator<5, 8>, Comparison.Lower>>,
  Expect<Equal<Comparator<5, 0>, Comparison.Greater>>,
  Expect<Equal<Comparator<-5, 0>, Comparison.Lower>>,
  Expect<Equal<Comparator<0, 0>, Comparison.Equal>>,
  Expect<Equal<Comparator<0, -5>, Comparison.Greater>>,
  Expect<Equal<Comparator<5, -3>, Comparison.Greater>>,
  Expect<Equal<Comparator<5, -7>, Comparison.Greater>>,
  Expect<Equal<Comparator<-5, -7>, Comparison.Greater>>,
  Expect<Equal<Comparator<-5, -3>, Comparison.Lower>>,
  Expect<Equal<Comparator<-25, -30>, Comparison.Greater>>,
  Expect<Equal<Comparator<15, -23>, Comparison.Greater>>,
  Expect<Equal<Comparator<40, 37>, Comparison.Greater>>,
  Expect<Equal<Comparator<-36, 36>, Comparison.Lower>>,
  Expect<Equal<Comparator<27, 27>, Comparison.Equal>>,
  Expect<Equal<Comparator<-38, -38>, Comparison.Equal>>,
]
@akcyp akcyp added answer Share answers/solutions to a question en in English labels Sep 28, 2021
@github-actions github-actions bot added the 274 label Sep 28, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
274 answer Share answers/solutions to a question en in English
Projects
None yet
Development

No branches or pull requests

1 participant