# lydiacupery's solution

## to List Ops in the TypeScript Track

Published at Apr 01 2019 · 0 comments
Instructions
Test suite
Solution

#### Note:

This exercise has changed since this solution was written.

Implement basic list operations.

In functional languages list operations like `length`, `map`, and `reduce` are very common. Implement a series of basic list operations, without using existing functions.

## Setup

Go through the setup instructions for TypeScript to install the necessary dependencies:

http://exercism.io/languages/typescript

## Requirements

Install assignment dependencies:

``````\$ yarn install
``````

## Making the test suite pass

Execute the tests with:

``````\$ yarn test
``````

## Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

### list-ops.test.ts

``````import List from './list-ops'

describe('append entries to a list and return the new list', () => {
it('empty lists', () => {
const list1 = new List()
const list2 = new List()
expect(list1.append(list2)).toEqual(new List())
})

xit('empty list to list', () => {
const list1 = new List([1, 2, 3, 4])
const list2 = new List<number>()
expect(list1.append(list2)).toEqual(list1)
})

xit('non-empty lists', () => {
const list1 = new List([1, 2])
const list2 = new List([2, 3, 4, 5])
expect(list1.append(list2).values).toEqual([1, 2, 2, 3, 4, 5])
})
})

describe('concat lists and lists of lists into new list', () => {
xit('empty list', () => {
const list1 = new List()
const list2 = new List([])
expect(list1.concat(list2).values).toEqual([])
})

xit('list of lists', () => {
const list1 = new List([1, 2])
const list2 = new List([3])
const list3 = new List([])
const list4 = new List([4, 5, 6])
const listOfLists = new List([list2, list3, list4])
expect(list1.concat(listOfLists).values).toEqual([1, 2, 3, 4, 5, 6])
})
})

describe('filter list returning only values that satisfy the filter function', () => {
xit('empty list', () => {
const list1 = new List([])
expect(list1.filter((el: number) => el % 2 === 1).values).toEqual([])
})

xit('non empty list', () => {
const list1 = new List([1, 2, 3, 5])
expect(list1.filter((el: number) => el % 2 === 1).values).toEqual([1, 3, 5])
})
})

describe('returns the length of a list', () => {
xit('empty list', () => {
const list1 = new List()
expect(list1.length()).toEqual(0)
})

xit('non-empty list', () => {
const list1 = new List([1, 2, 3, 4])
expect(list1.length()).toEqual(4)
})
})

describe('returns a list of elements whose values equal the list value transformed by the mapping function', () => {
xit('empty list', () => {
const list1 = new List()
expect(list1.map((el: number) => ++el).values).toEqual([])
})

xit('non-empty list', () => {
const list1 = new List([1, 3, 5, 7])
expect(list1.map((el: number) => ++el).values).toEqual([2, 4, 6, 8])
})
})

describe('folds (reduces) the given list from the left with a function', () => {
xit('empty list', () => {
const list1 = new List()
expect(list1.foldl((acc: number, el: number) => el / acc, 2)).toEqual(2)
})

xit('division of integers', () => {
const list1 = new List([1, 2, 3, 4])
expect(list1.foldl((acc: number, el: number) => el / acc, 24)).toEqual(64)
})
})

describe('folds (reduces) the given list from the right with a function', () => {
xit('empty list', () => {
const list1 = new List()
expect(list1.foldr((acc: number, el: number) => el / acc, 2)).toEqual(2)
})

xit('division of integers', () => {
const list1 = new List([1, 2, 3, 4])
expect(list1.foldr((acc: number, el: number) => el / acc, 24)).toEqual(9)
})
})

describe('reverse the elements of a list', () => {
xit('empty list', () => {
const list1 = new List()
expect(list1.reverse().values).toEqual([])
})

xit('non-empty list', () => {
const list1 = new List([1, 3, 5, 7])
expect(list1.reverse().values).toEqual([7, 5, 3, 1])
})
})``````
``````export default class List<T> {
public values: T[] = []

constructor(items?: T[]){
if(items){
this.values = items
}
}

append(list: List<T>): List<T>{
for(const i in list.values){
this.values.push(list.values[i])
}
return this
}

concat(listOfLists: List<List<T>>): List<T>{
for(const i in listOfLists.values){
this.append(listOfLists.values[i])
}
return this
}

filter(fn: (el: T) => boolean): List<T>{
let newValues: T[] = []
for(const i in this.values){
if(fn(this.values[i])) {
newValues.push(this.values[i])
}
}
this.values = newValues
return this;
}

length(): number{
let count = -1
for(const i in this.values){
count = Number(i)
}
return count + 1
}

map(fn: (el:T) => T): List<T> {
for(const i in this.values){
this.values[i] = fn(this.values[i])
}
return this;
}

foldl(fn: (acc: T, el: T) => T, initial: T): T {
return this.leftFoldHelper(fn, initial, this)
}

leftFoldHelper(fn: (acc: T, el: T) => T, initial: T, list: List<T>): T {
if(list.length() == 0 ){
return initial
}
return fn(this.leftFoldHelper(fn,initial, new List(list.values.slice(0, list.length()-1))), list.values[list.length()-1])
}

foldr(fn: (acc: T, el: T) => T, initial: T): T {
return this.rightFoldHelper(fn, initial, this)
}

rightFoldHelper(fn: (acc: T, el: T) => T, initial: T, list: List<T>): T{
if(list.length() == 0 ){
return initial
}
return fn(this.rightFoldHelper(fn,initial, new List(list.values.slice(1, list.length()))), list.values[0])
}

reverse(): List<T> {
const reversedList: T[] = []
for(const i in this.values){
reversedList.push(this.values[this.length()-1-Number(i)])
}
this.values = reversedList
return this
}

}``````