09286-medium-firstuniquecharindex

Back

key point is find the ${Head}${Tail} extends ${any}${Char}${any}

Head + Char + Tail = T

type FirstUniqueCharIndex<
  T extends string,
  Head extends string = '',
  Count extends any[] = []
> = T extends `${infer Char}${infer Tail}`
  ? `${Head}${Tail}` extends `${any}${Char}${any}`
    ? FirstUniqueCharIndex<Tail, `${Head}${Char}`, [...Count, 1]>
    : Count['length']
  : -1;
  

Solution by sunupupup #33444

type Includes<T extends string, U extends string> = T extends `${string}${U}${string}` ? true : false;
type LengthOfString<S extends string, A extends string[] = []> = S extends `${infer U}${infer Rest}`
    ? LengthOfString<Rest, [U, ...A]>
    : A['length'];

type FirstUniqueCharIndex<T extends string, Prefix extends string = ''> = T extends `${infer F}${infer R}`
    ? Includes<`${Prefix}${R}`, F> extends true
        ? FirstUniqueCharIndex<R, `${Prefix}${F}`>
        : LengthOfString<Prefix>
    : -1;

Solution by kscory #33080

type FirstUniqueCharIndex<
  T extends string,
  U extends string = T,
  V extends unknown[] = []
> = T extends `${infer First}${infer Rest}`
  ? U extends `${string}${First}${string}${First}${string}`
  ? FirstUniqueCharIndex<Rest, U, [...V, unknown]>
  : V['length']
  : -1;

Solution by Robinsstudio #32940

type StringToTuple<T extends string, Acc extends string[] = []> = T extends `${infer F}${infer R}`
  ? StringToTuple<R, [...Acc, F]>
  : Acc

type FirstUniqueCharIndex<T extends string, VisitedChars extends string[] = []> = T extends `${infer F}${infer R}`
    ? F extends StringToTuple<R>[number] | VisitedChars[number]
      ? FirstUniqueCharIndex<R, [...VisitedChars, F]>
      : VisitedChars['length']
    : -1

Solution by keyurparalkar #32654

// your answers
type FirstUniqueCharIndex<
  T extends string,
  A extends string = "",
  I extends number[] = []
> = T extends `${infer F}${infer L}`
  ? `${A}${L}` extends `${string}${F}${string}`
    ? FirstUniqueCharIndex<L, `${A}${F}`, [...I, 1]>
    : I["length"]
  : -1;

Solution by GodCount #32429

type FirstUniqueCharIndex<
  T extends string,
  C extends 0[] = [],
  P extends string = ""
> = T extends `${infer F}${infer R}`
  ? `${P}${R}` extends `${string}${F}${string}`
    ? FirstUniqueCharIndex<R, [...C, 0], `${P}${F}`>
    : C["length"]
  : -1;

Solution by vangie #32207

// your answers

type FirstUniqueCharIndex<T extends string, C extends any[] = [], U = T> = 
  T extends `${infer S}${infer O}` ? 
    (U extends `${infer Q}${S}${O}` ? 
      (Q extends `${string}${S}${string}` ? FirstUniqueCharIndex<O, [1, ...C], U> : 
        O extends `${string}${S}${string}` ? FirstUniqueCharIndex<O, [1, ...C], U> : C['length']) 
    : never) 
  : -1;

Solution by tarotlwei #31745

type StrToTuple<S extends string> = S extends `${infer F}${infer Rest}`
  ? [F, ...StrToTuple<Rest>]
  : []

type FirstUniqueCharIndex<
  T extends string,
  L extends string = '',
  C extends any[] = [],
> = T extends `${L}${infer S}${infer Rest}`
  ? S extends StrToTuple<`${L}${Rest}`>[number]
    ? FirstUniqueCharIndex<T, `${L}${S}`, [...C, any]>
    : C['length']
  : -1

Solution by Minato1123 #31150

// your answers
type UniqueChars<T extends string, Used = never, UsedMoreThanOnce = never> = T extends `${infer F}${infer Rest}` ?  UniqueChars<Rest, Used | F, F extends Used ? UsedMoreThanOnce | F : UsedMoreThanOnce> : Exclude<Used, UsedMoreThanOnce>
type FirstUniqueCharIndex<T extends string, Counter extends never[] = [], U = UniqueChars<T>> = T extends `${infer F}${infer Rest}` ? F extends U ? Counter["length"] : FirstUniqueCharIndex<Rest, [never, ...Counter], U> : -1

UniqueChars<T> returns the unique characters in T as a union of characters. (The core part of this is Exclude<Used, UsedMoreThanOnce>).

In FirstUniqueCharIndex<T extends string, Counter extends never[] = [], U = UniqueChars<T>>, we can check whether infer F is unique by using F extends U.

The optional argument U is set to save the result of UniqueChars<T>.

Solution by Kakeru-Miyazaki #30896

type StringToUnion<S extends string, V extends any[] = []> = S extends `${infer First}${infer Rest}`
  ? StringToUnion<Rest, [...V, First]>
  : V[number];

type FirstUniqueCharIndex<S extends string, T extends unknown[] = []> = S extends `${infer F}${infer Rest}`
  ? F extends StringToUnion<Rest> | T[number]
    ? FirstUniqueCharIndex<Rest, [...T, F]>
    : T['length']
  : -1;

Solution by leejaehyup #30863

// 你的答案
type FirstUniqueCharIndex<T extends string, A extends string = '', U extends string[] = []> = T extends `${infer F}${infer R}` ? `${A}${R}` extends `${any}${F}${any}` ? FirstUniqueCharIndex<R, `${A}${F}`, [...U, '']> : U['length'] : -1

Solution by YE840926098 #30135

利用Count来存储从L中排出的L,当R中不存在L并且Count中也不存在L时,则说明他是唯一的

type FirstUniqueCharIndex<T extends string, Count extends string[] = []> = 
  T extends `${infer L}${infer R}` 
    ? R extends `${string}${L}${string}` 
      ? FirstUniqueCharIndex<R, [...Count, L]> : L extends Count[number]
      ? FirstUniqueCharIndex<R, [...Count, L]> : Count['length']
    : -1

Solution by sv-98-maxin #30125

type FirstUniqueCharIndex<
  T extends string,
  Res extends Array<string> = []
> = T extends `${infer Char}${infer Rest}`
  ? Char extends Res[number]
    ? FirstUniqueCharIndex<Rest, [...Res, Char]>
    : Rest extends `${string}${Char}${string}`
    ? FirstUniqueCharIndex<Rest, [...Res, Char]>
    : Res["length"]
  : -1;

Solution by DoubleWoodLin #28850

type UpdateRes<
  T extends Array<[string, number]>,
  U extends string
> = T extends [infer Item, ...infer Rest extends Array<[string, number]>]
  ? Item extends [U, infer Index]
    ? Rest
    : [Item, ...UpdateRes<Rest, U>]
  : [];

type FirstUniqueCharIndex<
  T extends string,
  Union extends string = "",
  Res extends Array<[string, number]> = [],
  Count extends unknown[] = []
> = T extends `${infer Char}${infer Rest}`
  ? Char extends Union
    ? FirstUniqueCharIndex<
        Rest,
        Union,
        UpdateRes<Res, Char>,
        [unknown, ...Count]
      >
    : FirstUniqueCharIndex<
        Rest,
        Union | Char,
        [...Res, [Char, Count["length"]]],
        [unknown, ...Count]
      >
  : Res extends []
  ? -1
  : Res[0][1];

Solution by DoubleWoodLin #28849

type FirstUniqueCharIndex<
  Chars extends string,
  ProcessedChars extends string = "",
  ProcessedCharArray extends string[] = []
> = Chars extends `${infer Head}${infer Tail}`
  ? `${ProcessedChars}${Tail}` extends `${string}${Head}${string}`
    ? FirstUniqueCharIndex<
        Tail,
        `${ProcessedChars}${Head}`,
        [...ProcessedCharArray, Head]
      >
    : ProcessedCharArray["length"]
  : -1;

Solution by yevhenpavliuk #28412

有点蠢但是思路还算清晰,但是算法上来看性能可能不好?

遍历字符串 s,通过 ${infer F}${infer E} 获取到第一项 F 字符,计算一下 F 字符在字符串 s 中有多少个,这里写了个 RepeatCharCount 类型来计算。

如果只有一个,那么久说明是第一个非重复字符,返回索引。

那么这里就需要记录索引,这种记录索引的,就只能通过数组 length 来处理,通过不断为数组添加元素,来得到当前是第几个

还需要注意的一点是,这里引入了第三个变量 O,用来保存原始的字符串 s,因为每次遍历的字符,都应该判断的是在字符串 s 中的个数

type RepeatCharCount<T extends string, U extends string, N extends any[] = []> = U extends `${infer F}${infer E}`
  ? T extends F
    ? RepeatCharCount<T, E, [...N, '']>
    : RepeatCharCount<T, E, [...N]>
  : N['length']

type FirstUniqueCharIndex<T extends string, N extends string[] = [], O extends string = T> = T extends `${infer F}${infer E}`
  ? RepeatCharCount<F, O> extends 1
    ? N['length']
    : FirstUniqueCharIndex<E, [...N, ''], T>
  : -1

Solution by linjunc #28151

// your answers
type FirstUniqueCharIndex<
  T extends string,
  U = T,
  A extends 0[] = []
> = T extends `${infer L}${infer R}`
  ? U extends `${string}${L}${string}${L}${string}`
    ? FirstUniqueCharIndex<R, T, [...A, 0]>
    : A["length"]
  : -1;

Solution by youpy #27968

type IsUnique<T, F> = T extends true ? (F extends true ? true : false) : false;
type IsPrevRepeat<P extends string[], T> = T extends P[number] ? false : true;
type IsRestRepeat<R, T extends string> = R extends `${string}${T}${string}`
  ? false
  : true;

type FirstUniqueCharIndex<
  T extends string,
  P extends string[] = []
> = T extends `${infer F}${infer R}`
  ? IsUnique<IsPrevRepeat<P, F>, IsRestRepeat<R, F>> extends true
    ? P["length"]
    : FirstUniqueCharIndex<R, [...P, F]>
  : -1;

never give up on your dream!

Solution by DoGukKim #27896

type Or<A, B> = A extends true ? true : B extends true ? true : false;
type Extends<T, U> = T extends U ? true : false;

type FirstUniqueCharIndex<
  T extends string,
  Skipped extends unknown[] = [],
  Seen extends string = never
> = T extends `${infer L}${infer Rest}`
  ? Or<Extends<L, Seen>, Extends<Rest, `${any}${L}${any}`>> extends true
    ? FirstUniqueCharIndex<Rest, [...Skipped, L], Seen | L>
    : Skipped["length"]
  : -1;

Solution by alythobani #27620

type FirstUniqueCharIndex<T extends string, B extends string[] = []> =
  T extends `${infer F}${infer R}`
    ? `${R}` extends `${string}${F}${string}`
      ? FirstUniqueCharIndex<R, [...B, F]>
      : F extends B[number]
        ? FirstUniqueCharIndex<R, [...B, F]>
        : B['length']
    : -1;

Solution by smileboyi #27215

type OneByString<T extends string, U extends string, i extends number[] = []> = T extends `${infer S}${infer R}` ? S extends U ? OneByString<R, U, [...i, 0]> : OneByString<R, U, i> : i['length']
type FirstUniqueCharIndex<T extends string,N extends string = T ,i extends string[] = []> = N extends `${infer S}${infer R}` ? OneByString<T, S> extends 1
    ? i['length'] : FirstUniqueCharIndex<T,R,[...i, S]> : -1

Solution by WangZiChu199910252255 #26903

type FirstUniqueCharIndex<T extends string, U extends any[] = []> = 
T extends `${infer L}${infer R}`
  ? R extends `${any}${L}${any}`
    ? FirstUniqueCharIndex<R, [...U, L]> 
    : L extends U[number] ? FirstUniqueCharIndex<R, [...U, L]> : U['length']
  : -1;

Solution by omittee #26693

// your answers

type StringToTuple<T, C extends unknown[] = []> = T extends '' ? C : T extends ${infer F}${infer R} ? StringToTuple<R, [...C, F]> : never type StingToUnion = StringToTuple[number] type FirstUniqueCharIndex<T extends string, C extends unknown[] = [], PRE extends string = ''> = C["length"] extends StringToTuple["length"] ? -1 : T extends ${infer F}${infer R} ? F extends StingToUnion<${PRE}${R}> ? FirstUniqueCharIndex<R, [...C, 1], ${PRE}${F}> : C["length"] : never

Solution by enochjs #26316

// your answers
type FirstUniqueCharIndex<
  S,
  Prefix extends string = "",
  Index extends never[] = []
> = S extends `${infer F}${infer Rest}`
  ? `${Prefix}${Rest}` extends `${infer A}${F}${infer B}`
    ? FirstUniqueCharIndex<Rest, `${Prefix}${F}`, [...Index, never]>
    : Index["length"]
  : -1;

Solution by DvYinPo #25901

// your answers
type FirstUniqueCharIndex<T extends string, Cur extends unknown[] = [], Prev extends string = ''> =
  T extends `${infer X}${infer Y}` 
  ? Y extends `${infer A}${X}${infer B}`
    ? FirstUniqueCharIndex<Y, [...Cur, X], `${Prev}${X}`> 
    : Prev extends `${infer A}${X}${infer B}`
      ? FirstUniqueCharIndex<Y, [...Cur, X], `${Prev}${X}`> 
      : Cur['length']
  : -1

Solution by kiki-zjq #25764

type StrToUnion<S extends string> = 
  S extends `${infer F}${infer Rest}` 
    ? F | StrToUnion<Rest>
    : never

type FirstUniqueCharIndex<T extends string, P extends string = '', C extends any[] = []> =
  T extends `${infer F}${infer Rest}`
    ? F extends StrToUnion<`${P}${Rest}`>
      ? FirstUniqueCharIndex<Rest,F , [...C, 1]>
      : C['length']
    : -1

Solution by Minato1123 #25254

Find the union of unique characters and then replicate the use of IndexOf with that

type UniqueCharacters<T extends string, Acc extends string = never, Unique extends string = never> =
  T extends `${infer Head}${infer Tail}`
  ? Head extends Acc
    ? UniqueCharacters<Tail, Acc, Exclude<Unique, Head>>
    : UniqueCharacters<Tail, Acc | Head, Unique | Head>
  : Unique

type FirstUniqueCharIndex<T extends string, Prev extends string[] = [], Unique = UniqueCharacters<T>> =
  T extends `${infer Head}${infer Tail}`
  ? Head extends Unique
    ? Prev["length"]
    : FirstUniqueCharIndex<Tail, [...Prev, Head], Unique>
  : -1

Solution by prenaissance #24931

type String2Union<T extends string> = T extends `${infer F}${infer R}`
  ? F | String2Union<R>
  : never
type FirstUniqueCharIndex<T extends string, C extends 1[] = [], P = never> = T extends `${infer F}${infer R}`
  ? F extends P
    ? FirstUniqueCharIndex<R, [...C, 1], P>
    : F extends String2Union<R>
      ? FirstUniqueCharIndex<R, [...C, 1], P | F>
      : C['length']
  : -1

Solution by Sun79 #24891

type Include<T extends string, U extends string> = T extends `${infer First}${infer Rest}`
? Equal<First, U> extends true
  ? true
  : Include<Rest, U>
: false

type FirstUniqueCharIndex<T extends string, Compare extends string = '', Counter extends unknown[] = []> = T extends `${infer First}${infer Rest}`
? Include<`${Compare}${Rest}`, First> extends true
  ? FirstUniqueCharIndex<Rest, `${Compare}${First}`, [...Counter, '']>
  : Counter['length']
: -1

Solution by NeylonR #24803

type FirstUniqueCharIndex<
  T extends string,
  Index extends number[] = [],
  Checked extends string = ''
> = T extends `${infer F}${infer R}`
  ? F extends Checked
    ? FirstUniqueCharIndex<R, [...Index, 1], Checked>
    : R extends `${infer _}${F}${infer __}`
    ? FirstUniqueCharIndex<R, [...Index, 1], Checked | F>
    : Index['length']
  : -1;

Solution by JohnLi1999 #24680