Skip to content

Commit

Permalink
Merge pull request #69 from lafith/master
Browse files Browse the repository at this point in the history
Corrected minor discrepancies in chp 3 and chp 4
  • Loading branch information
chrisvoncsefalvay committed Feb 23, 2021
2 parents ffa3a91 + ab2a311 commit 34a8876
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 76 deletions.
4 changes: 2 additions & 2 deletions _chapters/06-ex3.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ In fact, `+` is the 'shorthand' for over a hundred methods. You can see all of t
```julia
julia> import Base.+

julia> function +{LSD}(a::LSD, b::LSD)
julia> function +(a::LSD, b::LSD)
newpence = a.pence + b.pence
newshillings = a.shillings + b.shillings
newpounds = a.pounds + b.pounds
Expand All @@ -346,7 +346,7 @@ Indeed, `methods(+)` shows that the new method for two `LSD`s is registered:
+(x::Bool) at bool.jl:36
+(x::Bool,y::Bool) at bool.jl:39
...
+{LSD}(a::LSD,b::LSD) at none:2
+(a::LSD,b::LSD) at none:2
```

And now we know the price of biscuits and gravy:
Expand Down
79 changes: 44 additions & 35 deletions _chapters/07-ex4.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ Incidentally, `end` behaves like a number – so `prime_array[end-1]` returns th

#### Setting

If the indexable collection you are using is also mutable (e.g. an array), any of these methods will act as a pseudo-variable and will allow you to assign a value to it. Thus `prime_array[end] = 12` would change the last element of `prime_array` to 12. You also aren't restricted to a single element: calling `prime_array[2:4] = 0` would result in
If the indexable collection you are using is also mutable (e.g. an array), any of these methods will act as a pseudo-variable and will allow you to assign a value to it. Thus `prime_array[end] = 12` would change the last element of `prime_array` to 12. You also aren't restricted to a single element: calling `prime_array[2:4] .= 0` would result in

```julia
julia> prime_array
Expand Down Expand Up @@ -213,7 +213,7 @@ Similarly to `push!`, `unshift!` puts an element to the front of the collection:

#### `find` functions

There's a set of functions starting with find — such as `find()`, `findfirst()`, and `findnext()` — that you can use to get the index or indices of values within an indexable collection that match a specific value, or pass a test. These functions share three properties.
There's a set of functions starting with find — such as `findall()`, `findfirst()`, and `findnext()` — that you can use to get the index or indices of values within an indexable collection that match a specific value, or pass a test. These functions share three properties.

1. Their result is the _index or indices of the value sought or tested for_, with the _n\_th_ element's index being _n_, not _n-1_ as you might be used to from other languages.
2. You can use these functions in two principal forms: you can test for a value or you can test for a function, in which case the results will be the values for which the function returns `true`.
Expand All @@ -226,7 +226,7 @@ Let's try to find things within the following `Array`: `primes_and_one = [1,2,3,
`findfirst()` finds the first occurrence of a value and returns its index (or zero):

```julia
julia> findfirst(primes_and_one, 5)
julia> findfirst(isequal(5),primes_and_one)
4
```

Expand All @@ -236,15 +236,14 @@ As noted above, we can feed the `find` functions a function as well – it will
julia> findfirst(x -> x == 13, primes_and_one)
7
```
A lot more of this will be explored in Chapter [X].

You might have noticed that unlike in the case where you were searching for a particular value, _where you're searching by a function, the function comes first_. This is a little idiosyncrasy, but has to do with the way Julia determines what to do based on what it is provided with. A lot more of this will be explored in Chapter [X].
##### `findall()`

##### `find()`

`find()` returns an array of results. Thus, for instance, let's use the `isinteger` function to see which of our primes are integers (yet again, the result should not come as a shock):
`findall()` returns an array of results. Thus, for instance, let's use the `isinteger` function to see which of our primes are integers (yet again, the result should not come as a shock):

```julia
julia> find(isinteger, primes_and_one)
julia> findall(isinteger, primes_and_one)
10-element Array{Int64,1}:
1
2
Expand Down Expand Up @@ -274,12 +273,20 @@ As you might have noticed, when you use a function as an argument, you do not us

##### Get elements, not indices

So far, we've only been getting indices. How do we get the actual elements? The answer is, of course, by using our magical `[]`(square brackets) syntax. We'll also use this as a good opportunity to introduce a very useful function, `isprime()`, which returns `true` for primes and false otherwise:
So far, we've only been getting indices. How do we get the actual elements? The answer is, of course, by using our magical `[]`(square brackets) syntax. We'll also use this as a good opportunity to introduce a very useful function, `isprime()`, which returns `true` for primes and false otherwise.

First, you may have to add Primes package:

```julia
julia> import Pkg;
julia> Pkg.add("Primes")
```
If you already have it, let's import `isprime()` and use it:

```julia
julia> import Primes
julia> import Primes.isprime

julia> find(isprime, primes_and_one)
julia> findall(isprime, primes_and_one)
9-element Array{Int64,1}:
2
3
Expand All @@ -291,7 +298,7 @@ So far, we've only been getting indices. How do we get the actual elements? The
9
10

julia> primes_and_one[find(isprime,primes_and_one)]
julia> primes_and_one[findall(isprime,primes_and_one)]
9-element Array{Int64,1}:
2
3
Expand All @@ -307,7 +314,7 @@ So far, we've only been getting indices. How do we get the actual elements? The

#### Filtering

The `filter()` function works quite similar to `find`, except in this case returns only the elements that satisfy the condition (it is, effectively, a shorthand for the previous listing).
The `filter()` function works quite similar to `findall`, except in this case returns only the elements that satisfy the condition (it is, effectively, a shorthand for the previous listing).

```julia
julia> filter(isodd, primes_and_one)
Expand Down Expand Up @@ -397,10 +404,11 @@ For mutable indexable collections, such as arrays, you can use `sort!()`, which

#### Existence of a particular value

To find out whether an array has a particular value among its elements, you can use `in()`:
To find out whether an array has a particular value among its elements, you can use `in()`. `primes(1,10)` returns a collection of prime numbers from 1 to 10.

```julia
julia> in(2, primes)
julia> import Primes.primes
julia> in(2, primes(1,10))
true
```

Expand Down Expand Up @@ -515,7 +523,7 @@ One drawback of the bracket syntax is that if there is no entry for the key prov
in getindex at dict.jl:644
```

An alternative form of accessing a dictionary is using the `get()` function, which accepts a default value:
An alternative form of accessing a dictionary is using the `get()` function. `get()` takes three arguments, collection name, key, and a default value to print if the key is not present in the dictionary:

```julia
julia> get(statisticians, "Pearson", "I'm sorry, I don't know when this person lived.")
Expand All @@ -525,13 +533,6 @@ An alternative form of accessing a dictionary is using the `get()` function, whi
"I'm sorry, I don't know when this person lived."
```

An advantage of this is that you can create a default value, which the function will return if it cannot find the key requested. Unlike in some other programming languages, a default is _not optional_ for Julia:

```julia
julia> get(statisticians, "Kendall")
ERROR: `get` has no method matching get(::Dict{String,String}, ::String)
```

#### Get or create (`get!()`)

Because dicts are mutable, `get!()` can try to access a value by its key and create it if not found, then return the new value. Its syntax is identical to `get()`:
Expand All @@ -550,7 +551,7 @@ Because dicts are mutable, `get!()` can try to access a value by its key and cre

#### `pop!()`

`pop!()` returns the key-value array matching the key. If the key does not exist, it returns an optional default value or throws an error:
`pop!()` delete and returns the value matching the key. If the key does not exist, it returns an optional default value or throws an error:

```julia
julia> pop!(statisticians, "Gosset")
Expand Down Expand Up @@ -592,20 +593,20 @@ To check for the existence of a key without retrieving it, you can use `haskey()
false
```

You can also check for the existence of a key-value pair in a dict using the `in()` function you might be familiar with from arrays. Note that the notation of a key-value pair in this case will be in the form of a tuple `(key, value)` rather than using the associative array symbol `=>`:
You can also check for the existence of a key-value pair in a dict using the `in()` function you might be familiar with from arrays. Dicts look for `key=>value` pairs:

```julia
julia> in(("Bayes", "1702-1761"), statisticians)
julia> in("Bayes"=>"1702-1761", statisticians)
false
```

#### Retrieving keys or values

To retrieve all keys of a dict, use `keys()`. This will retrieve an object of type `KeyIterator`, which does just what the name suggests - it iterates through the keys of an array. This will be useful later on when we want to iterate through the dictionary by keys:
To retrieve all keys of a dict, use `keys()`. This will retrieve an object of type `KeySet`, which does just what the name suggests - it iterates through the keys of an array. This will be useful later on when we want to iterate through the dictionary by keys:

```julia
julia> keys(statisticians)
KeyIterator for a Dict{String,String} with 3 entries. Keys:
KeySet for a Dict{String,String} with 3 entries. Keys:
"Galton"
"Pearson"
"Kendall"
Expand All @@ -627,7 +628,7 @@ You can retrieve values, predictably, by using the `values()` function:
You may have noticed that dicts are unordered. Even a dict generated by reference to a range, such as the one seen above, will not be in any particular order:

```julia
julia> [i => sqrt(i) for i = 1:2:15]
julia> Dict([i => sqrt(i) for i = 1:2:15])
Dict{Int64,Float64} with 8 entries:
7 => 2.6457513110645907
9 => 3.0
Expand Down Expand Up @@ -731,21 +732,25 @@ To create a set, use the `Set()` constructor function. You can create a set that

```julia
julia> primes = Set()
Set{Any}({})
Set{Any}()
```

– or you can specify what sort of data types it would accept:

```julia
julia> primes = Set{Int64}()
Set{Int64}({})
Set{Int64}()
```

You can create and fill sets in one go by listing elements surrounded by curly braces `{}`, and if you surround the elements with square brackets `[]` instead of curly braces `{}` Julia will guess the type:
You can create and fill sets in one go by listing elements surrounded by square brackets `[]`:

```julia
julia> mersenne_primes_set = Set([3, 7, 31, 127])
Set([7,31,3,127])
Set{Int64} with 4 elements:
7
31
3
127
```

### Set operations
Expand All @@ -763,7 +768,8 @@ To find shared actors, we can use `intersect()`:
```julia
julia> intersect(lotr_actors, matrix_actors)
Set(String["Hugo Weaving"])
Set{String} with 1 element:
"Hugo Weaving"
```
To find actors who only starred in _Lord of the Rings_ but not in _The Matrix_, we can use `setdiff()`, which shows all elements that are in the first `Set` but not the second:
Expand All @@ -777,7 +783,10 @@ Finally, we can see actors who played in either of the movies, by using `union()
```julia
julia> union(lotr_actors, matrix_actors)
Set(String["Elijah Wood","Ian McKellen","Hugo Weaving","Keanu Reeves","Lawrence Fishburne","Viggo Mortensen"])
Set{String} with 3 elements:
"Elijah Wood"
"Viggo Mortensen"
"Ian McKellen"
```
Expand Down
58 changes: 19 additions & 39 deletions _chapters/08-ex5.md
Original file line number Diff line number Diff line change
Expand Up @@ -244,39 +244,39 @@ If you are familiar with regular expressions, plod ahead! However, if

looks like gobbledygook to you or you feel your regex fu is a little rusty, put down this book and consult the [Regex cheatsheet](http://www.rexegg.com/regex-quickstart.html#ref) or, even better, [Jeffrey Friedl's amazing book on mastering regexes](http://regex.info/book.html).

### Finding and replacing using the `search()` function
### Finding Substring

If you are only concerned with finding a single instance of a search term within a string, the `search()` function returns the range index of where the search expression appears:
If you are only concerned with finding a single instance of a search term within a string, the `findfirst()` function returns the range index of where the search expression appears:

```julia
julia> search(declaration, "Government")
julia> findfirst("Government",declaration)
241:250

```

`search()` also accepts regular expressions:
`findfirst()` also accepts regular expressions:

```julia
julia> search(declaration, r"th.{2,3}")
julia> findfirst(r"th.{2,3}", declaration)
9:13

```

To retrieve the result, rather than its index, you can pass the resulting index off to the string as the subsetting range, using the square bracket `[]` syntax:

```julia
julia> declaration[search(declaration, r"th.{2,3}")]
julia> declaration[findfirst(r"th.{2,3}", declaration)]
"these"

```

Ah, so that's the word it found!

Where a search string is not found, `search()` will yield `0:-1`. That is an odd result, until you realise the reason: for any string `s`, `s[0:-1]` will necessarily yield `""` (that is, an empty string).
Where a search string is not found, `findfirst()` will yield `nothing`.

### Finding using the `match()` family of functions

The problem with `search()` is that it retrieves one, and only one, result – the first within the string passed to it. The `match()` family of functions can help us with finding more results:
The problem with `findfirst()` is that it retrieves one, and only one, result – the first within the string passed to it. The `match()` family of functions can help us with finding more results:

- `match()` retrieves _either the first match or nothing_ within the text,
- `matchall()` returns _an array of all matching substrings_, and
Expand All @@ -299,7 +299,7 @@ is valid, while
yields an error:

```julia
ERROR: `match` has no method matching match(::String, ::String)
ERROR: MethodError: no method matching match(::String, ::String)

```

Expand Down Expand Up @@ -329,7 +329,7 @@ To illustrate, let's consider the result of a `match()` call, which will be intr

#### `match()`

`match()` retrieves the first match or nothing - in this sense, it is rather similar to `search()`:
`match()` retrieves the first match or nothing - in this sense, it is rather similar to `findfirst()`:

```julia
julia> match(r"That .*?,", declaration)
Expand All @@ -339,18 +339,6 @@ To illustrate, let's consider the result of a `match()` call, which will be intr

The result is a `RegexMatch` object. The object can be inspected using `.match` (e.g. `match(r"truths", declaration).match`).

#### `matchall()`

`matchall()` returns an array of matching substrings, which is sometimes a little easier to use:

```julia
julia> matchall(r"That .*?,", declaration)
2-element Array{SubString{UTF8String},1}:
"That to secure these rights,"
"That whenever any Form of Government becomes destructive of these ends,"

```

#### `eachmatch()`

`eachmatch()` returns an object known as an iterator, specifically of the type `RegexMatchIterator`. We have on and off encountered iterators, but we will not really deal with them in depth until chapter [X], which deals with control flow. Suffice it to say an iterator is an object that contains a list of items that can be iterated through. The iterator will iterate over a list of `RegexMatch` objects, so if we want the results themselves, we will need to call the `.match` method on each of them:
Expand All @@ -361,24 +349,23 @@ The result is a `RegexMatch` object. The object can be inspected using `.match`
end

```

The result is quite similar to that returned by `matchall()`:
gives following result:

```julia
A matching search result is: That to secure these rights,
A matching search result is: That whenever any Form of Government becomes destructive of these ends,

```

#### `ismatch()`
#### `occursin()`

`ismatch()` returns a boolean value depending on whether the search text contains a match for the regex provided.
`occursin()` returns a boolean value depending on whether the search text contains a match for the regex provided.

```julia
julia> ismatch(r"truth(s)?", declaration)
julia> occursin(r"truth(s)?", declaration)
true

julia> ismatch(r"sausage(s)?", declaration)
julia> occursin(r"sausage(s)?", declaration)
false

```
Expand All @@ -388,18 +375,11 @@ The result is quite similar to that returned by `matchall()`:
Julia can replace substrings using the `replace()` syntax... let's try putting some sausages into the Declaration of Independence!

```julia
julia> replace(declaration, "truth", "sausage")
julia> replace(declaration, "truth"=>"sausage",count=1)
"We hold these sausages to be self-evident, that all men are created equal,..."

```

An interesting feature of `replace()` is that the replacement does not need to be a string. In fact, it is possible to pass a function as the third argument (as always, without the parentheses `()` that signify a function call). Julia will interpret this as 'replace the substring with the result of passing the substring to this function':

```julia
julia> replace(declaration, "truth", uppercase)
"We hold these TRUTHs to be self-evident, that all men are created equal,..."

```
By increasing the value of count you can replace remaining "truth".

Much more dignified than self-evident sausages, I'd say! At risk of repeating myself, it is important to note that since strings are immutable, `replace()` merely returns a copy of the string with the search string replaced by the replacement string or the result of the replacement function, and the original string itself will remain unaffected.

Expand Down Expand Up @@ -435,8 +415,8 @@ Case transformations are functions that act on `String`s and transform character
|:--------:|--------|--------|
| `uppercase()` | Converts the entire string to upper-case characters | `WE HOLD THESE TRUTHS TO BE SELF-EVIDENT` |
| `lowercase()` | Converts the entire string to lower-case characters | `we hold these truths to be self-evident` |
| `ucfirst()` | Converts the first character of the string to upper-case | `We hold these truths to be self-evident` |
| `lcfirst()` | Converts the first character of the string ot lower-case | `we hold these truths to be self-evident` |
| `uppercasefirst()` | Converts the first character of the string to upper-case | `We hold these truths to be self-evident` |
| `lowercasefirst()` | Converts the first character of the string ot lower-case | `we hold these truths to be self-evident` |

### Testing and attributes

Expand Down

0 comments on commit 34a8876

Please sign in to comment.