From 12635511af58636ee57fc39699f841f412e2b17f Mon Sep 17 00:00:00 2001
From: Pascal Syma
Date: Sun, 7 Sep 2025 03:09:37 +0200
Subject: [PATCH] Add stats
---
src/pages/HomeView.vue | 2 +
src/pages/StatsView.vue | 66 +++++++++++++++++-
src/stores/tram.ts | 6 +-
src/utils/array.ts | 150 ++++++++++++++++++++++++++++++++++++++++
src/utils/typeGroup.ts | 9 +++
5 files changed, 228 insertions(+), 5 deletions(-)
create mode 100644 src/utils/array.ts
create mode 100644 src/utils/typeGroup.ts
diff --git a/src/pages/HomeView.vue b/src/pages/HomeView.vue
index 43c20ae..123e7e5 100644
--- a/src/pages/HomeView.vue
+++ b/src/pages/HomeView.vue
@@ -11,6 +11,7 @@ import {
VaCardActions,
VaCardContent,
VaCardTitle,
+ VaDivider,
VaForm,
VaIcon,
VaInput
@@ -88,6 +89,7 @@ function add() {
>Gesehen
+
diff --git a/src/pages/StatsView.vue b/src/pages/StatsView.vue
index 06c9c88..662dc6d 100644
--- a/src/pages/StatsView.vue
+++ b/src/pages/StatsView.vue
@@ -1,7 +1,69 @@
-
+
- Stats
+
+ Statistiken
+
+
+
+ Nach Typ
+
+
+
+
{{ idsOf(group.elements) }}:
+
+
+
+
+
+
+ Quick stats
+
+
+
+
+
+
+
+
+
+
diff --git a/src/stores/tram.ts b/src/stores/tram.ts
index 487f582..6e78100 100644
--- a/src/stores/tram.ts
+++ b/src/stores/tram.ts
@@ -1,12 +1,12 @@
import { defineStore } from 'pinia';
import { computed, reactive } from 'vue';
-export const type: [number, number, boolean, string][] = [
+export type CarType = [number, number, boolean, string];
+export const type: CarType[] = [
[3101, 3143, true, 'GT8N-1 - Bombardier Flexity Classic'],
[3201, 3249, true, 'GT8N-2 - Siemens Avenio'],
[3401, 3435, true, 'GT8N-2 - Siemens Avenio'],
- [4001, 4005, false, 'Solobus Mercedes eCitaro O 530 C2'],
- [4006, 4020, false, 'Solobus Mercedes eCitaro O 530 C2'],
+ [4001, 4020, false, 'Solobus Mercedes eCitaro O 530 C2'],
[4061, 4075, false, 'Solobus Mercedes Citaro O 530 C2'],
[4076, 4090, false, 'Solobus Mercedes Citaro O 530 C2 hybrid'],
[4150, 4151, false, 'Solobus MAN Lion“s City A21 NL 280'],
diff --git a/src/utils/array.ts b/src/utils/array.ts
new file mode 100644
index 0000000..cd63da8
--- /dev/null
+++ b/src/utils/array.ts
@@ -0,0 +1,150 @@
+/**
+ * Returns the sum of all the elements of a numeric array.
+ * @param arr Numeric array.
+ */
+export function sumArray(arr: ReadonlyArray): number {
+ return sumBy(arr, (a) => a);
+}
+
+/**
+ * Returns the sum of all the elements of any array,
+ * given a lamda function to receive the numeric representation of each element.
+ * @param arr Any array.
+ * @param by Map element to number or string, which will be interpreted as a number.
+ */
+export function sumBy(arr: ReadonlyArray, by: (element: E) => number | string): number {
+ return arr.reduce((sum, element) => sum + Number(by(element)), 0);
+}
+
+/**
+ * Returns the product of a numeric array.
+ * @param arr Numeric array.
+ */
+export function multArray(arr: ReadonlyArray): number {
+ return multBy(arr, (a) => a);
+}
+
+/**
+ * Returns the product of any array,
+ * given a lamda function to receive the numeric representation of each element.
+ * @param arr Any array.
+ * @param by Map element to number or string, which will be interpreted as a number.
+ */
+export function multBy(arr: ReadonlyArray, by: (element: E) => number | string): number {
+ if (arr.length <= 0) {
+ return 0;
+ }
+ return arr.reduce((sum, element) => sum * Number(by(element)), 1);
+}
+
+/**
+ * Group an array by a given key.
+ * @param arr Any array.
+ * @param by Map element to key.
+ * @param equals Check if two keys are identical. Defaults to strict equality.
+ */
+export function groupBy(
+ arr: ReadonlyArray,
+ by: (element: E) => K,
+ equals: (a: K, b: K) => boolean = (a, b) => a === b
+): { key: K; elements: Array }[] {
+ return arr.reduce(
+ (groups, element) => {
+ const key = by(element);
+ const index = groups.findIndex((e) => equals(e.key, key));
+
+ if (index < 0) {
+ // New key found, add to group array.
+ groups.push({ key, elements: [element] });
+ return groups;
+ }
+
+ const existing = groups[index];
+ existing.elements.push(element);
+
+ return groups;
+ },
+ [] as { key: K; elements: Array }[]
+ );
+}
+
+/**
+ * Return the middle Element of an array, rounding up.
+ * Returns undefined for empty arrays without throwing!
+ *
+ * @example
+ * ```typescript
+ * getMiddleElement([1, 2, 3, 4]) === 3
+ * getMiddleElement([1, 2, 3]) === 2
+ * getMiddleElement([1]) === 1
+ * getMiddleElement([]) === undefined
+ * ```
+ * @param arr
+ */
+export function getMiddleElement(arr: ReadonlyArray) {
+ return arr[Math.floor(arr.length / 2)];
+}
+
+/**
+ * Returns an array with every combination of every element in an array.
+ * The combination array will have a length of `n * (n-1)` for an array of length `n`.
+ * @example
+ * ```typescript
+ * const arr = [0, 1, 2]
+ *
+ * combinations(arr) === [
+ * {a: 0, b: 1},
+ * {a: 0, b: 2},
+ * {a: 1, b: 0},
+ * {a: 1, b: 2},
+ * {a: 2, b: 0},
+ * {a: 2, b: 1},
+ * ]
+ * ```
+ * @param arr
+ */
+export function combinations(arr: ReadonlyArray): { a: E; b: E }[] {
+ return arr
+ .flatMap((a, _, arr) => arr.flatMap((b) => (a !== b ? [{ a, b }] : null)))
+ .filter((c) => !!c);
+}
+
+/**
+ * Returns an array with every unique combination of every element in an array.
+ * The combination array will have a length of `n! / ((n-2)! * 2)` for an array of length `n`.
+ * @example
+ * ```typescript
+ * const arr = [0, 1, 2]
+ *
+ * combinations(arr) === [
+ * {a: 0, b: 1},
+ * {a: 0, b: 2},
+ * {a: 1, b: 2}
+ * ]
+ * ```
+ * @param arr
+ */
+export function uniqueCombinations(arr: ReadonlyArray): { a: E; b: E }[] {
+ return arr.flatMap((a, aI) => arr.flatMap((b, bI) => (a !== b && aI > bI ? [{ a, b }] : [])));
+}
+
+/**
+ * Returns a filter lambda to be used in array.filter() to only allow the
+ * first occurrence of duplicate values.
+ * @param isEqual Custom equality check, defaults to `a === b`
+ */
+export function unique(isEqual: (a: E, b: E) => boolean = (a, b) => a === b) {
+ return (self: E, index: number, arr: ReadonlyArray) =>
+ arr.findIndex((v) => isEqual(v, self)) === index;
+}
+
+/**
+ * Replace a char in a two-dimensional array of strings.
+ * @param arr two-dimensional string array
+ * @param x column
+ * @param y row
+ * @param char Char
+ */
+export function replaceChar(arr: string[], x: number, y: number, char: string) {
+ arr[y] = arr[y].substring(0, x) + char + arr[y].substring(x + char.length);
+}
diff --git a/src/utils/typeGroup.ts b/src/utils/typeGroup.ts
new file mode 100644
index 0000000..94024cd
--- /dev/null
+++ b/src/utils/typeGroup.ts
@@ -0,0 +1,9 @@
+import type { CarType } from '@/stores/tram.ts';
+
+export function idsOf(elements: CarType[]): string {
+ if (elements.length <= 0) {
+ return '';
+ }
+
+ return elements.map((t) => (t[0] === t[1] ? t[0] : `${t[0]}-${t[1]}`)).join(', ');
+}