Convert an array with three dimensions into a two-dimensional array that includes tuples with two immutable string values

Consider the array below with multiple dimensions:

type ParsedLine = [string, string];
type ParsedLines = [ParsedLine, ParsedLine]

const myArray: (ParsedLine | ParsedLines)[] = [
  ['something', 'somethingElse'],
  [['foo', 'bar'], ['baz','qux']],
  ['another', 'yetAnother']
];

The expected outcome is a 2-dimensional array:

// [['something','something-else'],['foo','bar'],['baz','qux'],['another','yetAnother']]

I have explored the flatten method from Lodash, but it only produces a 1-dimensional array.

Currently, I am using the following approach:

flattenArray(multidimensionalArray: (ParsedLine | ParsedLines)[]): ParsedLine[] {

  const flatArray: ParsedLine[] = [];

  multidimensionalArray.forEach((item): any => {
    // Why does 'item' need a typecast here?
    const containsSubArray = (item as Array <ParsedLine>).filter((subItem) => Array.isArray(subItem));
    if (containsSubArray.length === 0) {
      flatArray.push(item as ParsedLine);
    } else {
      flatArray.push((item as ParsedLines)[0]);
      flatArray.push((item as ParsedLines)[1]);
    }
  });

  return flatArray;
}

console.log(flattenArray(myArray));

Although this code provides the correct output, it lacks readability and immutability due to the use of the push method.

Furthermore, the necessity to cast 'item' raises questions about whether .filter() can work effectively on the ParsedLine tuple type.

Answer №1

When iterating through each element in the myArray, it is necessary to determine whether it belongs to a ParsedLine or a ParsedLines. By checking if the value of x is of type ParsedLine | ParsedLines and verifying if x[0] is a string, you can distinguish between them. However, the control flow analysis built into the compiler does not automatically narrow down the type of x as ParsedLine | ParsedLines is not a discriminated union. To guide the compiler based on your logic, consider creating a user-defined type guard function with a type predicate return type:

const isParsedLine = (x: ParsedLines | ParsedLine): x is ParsedLine =>
  typeof x[0] === "string";

By calling isParsedLine(x), the compiler will interpret a true result as x being a ParsedLine, and a false result as x being a ParsedLines.


For each entry cur in myArray, the goal is to add it to flattenedArray if it's a ParsedLine, or add its individual entries if it's a ParsedLines. One approach is to utilize Array.prototype.reduce() to append either cur or ...cur to the accumulator:

const flattenedArray = myArray.reduce<ParsedLine[]>(
  (acc, cur) => isParsedLine(cur) ? [...acc, cur] : [...acc, ...cur],
  []
);

This code snippet could be optimized further by unconditionally adding [...acc, :

const flattenedArray = myArray.reduce<ParsedLine[]>(
  (acc, cur) => [...acc, ...isParsedLine(cur) ? [cur] : cur],
  []
);

If available in your environment, you may even simplify it using Array.prototype.flatMap():

const flattenedArray = myArray.flatMap(
  cur => isParsedLine(cur) ? [cur] : cur
);

All these methods yield the same outcome:

console.log(flattenedArray);
// [["something", "somethingElse"], ["foo", "bar"], 
//  ["baz", "qux"], ["another", "yetAnother"]] 

Playground link to code

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Angular Error TS2339: The property 'car' is missing from type 'Array of Vehicles'

Encountering Angular Error TS2339: Property 'vehicle' is not found on type 'Vehicle[]'. The error is occurring on data.vehicle.results. Any thoughts on what could be causing this issue? Is the problem related to the Vehicle model? I hav ...

Error message: The provider is not being recognized by react-redux while using NextJS with RTK and

Struggling to integrate Redux RTK into my Next JS 13.4 app has been quite the challenge. No matter how many tutorials I follow, I keep encountering the same error in my provider.ts file. 'use client' import { store } from './store'; imp ...

Having trouble getting webpack to transpile typescript to ES5?

Despite following official guides and various tutorials, I am still facing an issue with compiling my code to ES5 using TypeScript and webpack. The problem is that the final bundle.js file always contains arrow functions. Here is a snippet from my webpack ...

Encountering challenges while integrating Angular with a Laravel forum creation project

Currently, I am working on building a forum application that involves users, posts, and comments using Laravel. However, the next step in my project requires integrating Angular, which is new territory for me and I'm not sure where to start. I have a ...

What is the correct format for an array so that the fputcsv result will display horizontally instead of vertically?

When I inspect the $array in my browser's source code, it looks like this: Array( [0] => 2015-01-15 [1] => 2015-02-15 [2] => 2015-03-15 ) To export this array to a CSV file, I used the following code; $fp = fopen("file.csv", "w"); fp ...

Include a character in a tube using Angular

Hey everyone, I have a pipe that currently returns each word with the first letter uppercase and the rest lowercase. It also removes any non-English characters from the value. I'm trying to figure out how to add the ':' character so it will ...

Replace elements for a specific key in a multidimensional array by looping through each element until the key is found and replaced, ensuring

Looking to update the array recursively by replacing the content of arrays with a [myKey] key with different values ([foo] => bar, [bar] => foo). Avoiding the use of references and instead focusing on refactoring existing code. Array ( [objects] ...

What is the best way to sift through an array and extract only the values that correspond with a user's input?

In my HTML file, I have an input field and a button element within the body section. Here is how they are structured: <input type="text" name="searchBar" id="searchBar"> <button onclick="returnText()">Sub ...

Exporting the interface for the state of the redux store

After setting up a redux module, I have organized the following files: //state.tsx export default interface State { readonly user: any; readonly isLoggedIn: boolean; } //types.tsx export default { REQUEST: 'authentication/REQUEST', SUC ...

Managing Data Types in a React and Express Application

I am working on a project that includes both a React client and a Node-Express backend. Currently, my React app is running with TypeScript and I am looking to switch my backend to TypeScript as well. At the moment, my project structure consists of a clien ...

What is the best way to combine the attributes of multiple objects within a union type?

I have a clearly defined schema type Schema = { a: { a: 1 } b: { b: 2 } } I am in need of a function that can generate objects that adhere to multiple schemas. function createObject<K extends keyof Schema>(schema: Array<K>, obj: Sche ...

Create an interface that inherits from a class

I am currently in the process of converting some code that attempts to create an instance of http.ServerResponse. However, typescript is throwing an error: [ts] Property 'ServerResponse' does not exist on type 'typeof "http"'. I hav ...

Does the term 'alias' hold a special significance in programming?

Utilizing Angular 2 and Typescript, I have a component with a property defined as follows: alias: string; Attempting to bind this property to an input tag in my template like so: <input class="form-control" type="text" required ...

Transforming Json data into an Object using Angular 6

https://i.stack.imgur.com/JKUpL.png This is the current format of data I am receiving from the server, but I would like it to be in the form of an Object. public getOrder(): Observable < ORDERS > { return this._http.get < ORDERS > (`${thi ...

Issue encountered with dynamic ngStyle variable: ERROR Error: Unable to locate a supporting object 'ngStyleSmall'

I have defined two variables for ngstyle ngStyleSmall = { width: '150px !important', 'max-width': '150px', }; ngStylemedium = { width: '250px !important', 'max-width&apo ...

Develop a type definition utilizing dotted paths from a recursive object model

Working with TypeScript, I am dealing with a nested object structure of functions defined as: type CallbackFn = (args: any) => any type CallbackObj = { [key: string]: CallbackFn | CallbackObj } const callbacks = { foo: function(args: { x: num }): st ...

What steps can I take to resolve the 'Object may be null' error in TypeScript?

I am facing a similar issue to the one discussed in this thread, where I am using Draft.js with React and Typescript. After following the code example provided in their documentation, I encountered the 'Object is possibly 'null'' error ...

What are the drawbacks of introducing a dependency within the constructor?

I'm struggling to understand why breaking the rules is considered bad. import {DepClass} from './di-import' // <- some dependency imports here class DI1 { dep1: DepClass constructor(){ this.dep1 = new DepClass() // ...

TypeScript's TypeGuard wandering aimlessly within the enumerator

I'm puzzled by the fact that filter.formatter (in the penultimate line) is showing as undefined even though I have already confirmed its existence: type Filter = { formatter?: { index: number, func: (value: string) => void ...

Mastering the art of calculating month differences on TypeScript dates in an Angular environment

Currently, I am working with Angular 7. Suppose I have a fixed rate X, for example, an amount I need to pay each month. Now, if I have two specified dates startDate and endDate, I want to calculate the total payment due for this given time period. To prov ...