class: center, middle, inverse, title-slide # Plotting ## With ggplot2 ### The R Bootcamp
Twitter:
@therbootcamp
### January 2018 --- # You can do amazing plots in R! - As good as R is for statistics, it's as good if not better for plots.  --- .pull-left45[ ## Base R Plotting There are different frameworks for doing plotting in R. The classic framework is known as Base R plotting. In Base R plotting, there is a separate function for each 'type' of plot | Plot type| Function| |:------|:----| | Bar plot| `barplot()`| | Box plot| `boxplot()`| | Scatterplot| `plot()`| ] .pull-right5[ ```r # Histogram in base R hist(x = ChickWeight$weight, xlab = "Weight", ylab = "Frequency", main = "Histogram in Base R") ```  ] --- .pull-left45[ ## Base R Plotting There are different frameworks for doing plotting in R. The classic framework is known as Base R plotting. In Base R plotting, there is a separate function for each 'type' of plot | Plot type| Function| |:------|:----| | Bar plot| `barplot()`| | Box plot| `boxplot()`| | Scatterplot| `plot()`| ] .pull-right5[ ```r # Boxplot in base R boxplot(formula = cty ~ trans, data = mpg, xlab = "Transmission", ylab = "City miles per gallon", main = "Boxplot in Base R") ```  ] --- .pull-left45[ ## Base R Plotting There are different frameworks for doing plotting in R. The classic framework is known as Base R plotting. In Base R plotting, there is a separate function for each 'type' of plot | Plot type| Function| |:------|:----| | Bar plot| `barplot()`| | Box plot| `boxplot()`| | Scatterplot| `plot()`| ] .pull-right5[ ```r # Scatterplot in base R plot(x = economics$date, y = economics$unemploy, xlab = "Date", ylab = "Unemployment rate", main = "Scatterplot in Base R" ) ```  ] --- .pull-left5[ ## Problems with Base R plotting
 Complex plots can quickly require a LOT of code.

 Default plots look pretty outdated

 No way to set plotting themes

 Can't store plots as objects to reference and update later

 ] .pull-right5[

 This plot would take a lot of code in Base R  ] --- ## ggplot2 .pull-left45[
 How do we make elegant, easy to program plots according to the grammar of graphics in R?

 Answer: ggplot2

 One of the most widely used R packages, used to generate the vast majority of plots from R. ] .pull-right5[  ] --- ## Grammar of Graphics .pull-left5[

 1. A plot is built of simple building blocks

 2. By combining different building blocks, plots of any complexity can be created.

 3. Plots that look superficially different, can actually be created with very similar code.

 ] .pull-right5[  ] --- ## Grammar of Graphics .pull-left5[ The Grammar of graphics breaks down plots into several key pieces: | aesthetics| Description| |:------|:----| | Data| What dataframe contains the data?| | Aesthetics| What does the x-axis, y-axis, color (etc) represent?| | Geometries| What kind of geometric object do you want to plot?| | Facets| Should there be groups of plots?| | Statistics|What statistic summaries / transformations should be done?| | Coordinates| What is the scale of the axes?| | Theme| What should the overall plot look like?| ] .pull-right5[  ] --- ## Our goal .pull-left5[ - In this introduction, we'll introduce the basic building blocks of creating plots with ggplot2 by creating the following plot from the ground-up:  ] .pull-right45[ ### In the practical, you will create all of these!!  ] --- ## ggplot2 .pull-left6[  ] .pull-right4[ ### Load the ggplot2 package ```r # Load the tidyverse (includes ggplot2) library(tidyverse) ``` ### Or ```r # Load ggplot2 directly library(ggplot2) ``` ] --- ## `mpg` data .pull-left6[ The `mpg` data is a tibble of car data contained in the `ggplot2` package |manufacturer |model | cty| hwy|class | |:------------|:------------------|---:|---:|:----------| |land rover |range rover | 11| 15|suv | |hyundai |sonata | 19| 28|midsize | |toyota |camry | 21| 31|midsize | |jeep |grand cherokee 4wd | 15| 20|suv | |chevrolet |c1500 suburban 2wd | 14| 20|suv | |ford |mustang | 15| 23|subcompact | |volkswagen |new beetle | 29| 41|subcompact | |ford |expedition 2wd | 11| 17|suv | ] .pull-right3[

  ] --- ## Creating this plot .pull-left5[ **Data** - Use the `mpg` tibble **Aesthetics** - Show engine displacement (`disp`) on the x axis - Show highway miles per gallon (`hwy`) on the y-axis - Color plotting elements by the class of car (`class`) **Geometric objects** - Show data as points. - Add a regression line **Labels and themes** - Add plotting labels - Use a black and white plotting theme ] .pull-right5[ Our goal is to build the following plot step by step:  ] --- ## ggplot(data) .pull-left5[ - To create a ggplot2 object, use the `ggplot()` function. | argument| description| |:------|:----| | `data`| A dataframe (or tibble)| | `mapping`|A call to aes()| - Including only a `data` argument returns a blank plotting space, because we haven't specified any plotting *aesthetics* or *geometric objects* ] .pull-right5[ ```r ggplot(data = mpg) ```  ] --- ## ggplot(mapping = aes()) .pull-left4[ - An **aesthetic mapping** is a visual property of the objects in your plot. ### Common aesthetics | aesthetics| Description| |:------|:----| | `x`, `y`| Data mapped to coordinates| | `color`, `fill`| Border and fill colors| | `alpha`| Transparency| | `size`| Size| | `shape`| Shape| - Add aesthetics with the `aes()` function - Arguments can be columns in your dataframe, or in some cases fixed (i.e.; string or integer) values ] .pull-right5[ ```r ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) ```  ] --- ## Adding elements to plots with '+' .pull-left45[ - Once you have specified data with `data` argument, and global aesthetics with `mapping = aes()`, you can add additional elements to the plot with `+` - The `+` sign works just like the pipe `%>%` in dplyr. It just means "and then..." ```r ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + # and then... # MORE + (and then...) # MORE + (and then...) ``` ] .pull-right5[ ### ggplot uses `+` to add additional elements to a plot  ] --- ## Geometric objects (geoms) .pull-left4[ - A **geom** is a geometric object in a plot that represents data - To add a geom to a plot, just include ` + geom_X()` where X is the type of geom. ### Common geoms | geom| output| |:------|:----| | `geom_point()`| Points| | `geom_bar()`| Bar| | `geom_boxplot()`| Boxplot | `geom_count()`| Points with size reflecting frequency| | `geom_smooth()`| Smoothed line| ] .pull-right5[ ### Add a point geom with `geom_point()` ```r ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + geom_point() ```  ] --- .pull-left45[ ### geom_boxplot() ```r ggplot(data = mpg, mapping = aes(x = class, y = hwy, fill = class)) + geom_boxplot() ```  ] .pull-right45[ ### geom_violin() ```r ggplot(data = mpg, mapping = aes(x = class, y = hwy, fill = class)) + geom_violin() ```  ] --- .pull-left45[ ### geom_bar() ```r ggplot(data = mpg, mapping = aes(x = class, fill = class)) + geom_bar() ```  ] .pull-right45[ ### geom_count() ```r ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + geom_count() ```  ] --- .pull-left45[ ### geom_density() ```r ggplot(data = mpg, mapping = aes(x = hwy, fill = class)) + geom_density() ```  ] .pull-right45[ ### geom_tile() ```r ggplot(nba_long, mapping = aes(x = Name, y = measure, fill = value)) + geom_tile(col = "white") + scale_fill_gradientn(colors = c("red", "white", "blue")) + coord_flip() ```  ] --- ## Aesthetics .pull-left45[ > What plotting aesthetic is missing from the code below to make our plot on the right? ```r ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + geom_point() ```  ] .pull-right5[  ] --- ## Color aesthetic ```r ggplot(data = mpg, mapping = aes(x = displ, y = hwy, col = class)) + # Map mpg$class to color aes geom_point() # Add points that respect the aesthetics ```  --- ## Geometric objects (geoms) .pull-left45[ *Code WITHOUT color aesthetic* ```r ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + geom_point() ```  ] .pull-right45[ *Code WITH color aesthetic* ```r ggplot(data = mpg, mapping = aes(x = displ, y = hwy, col = class)) + geom_point() ```  ] --- ### What's next? .pull-left45[ ```r ggplot(data = mpg, mapping = aes(x = displ, y = hwy, col = class)) + geom_point() ```  ] .pull-right45[ Our goal
  ] --- ### Smoothed lines with `geom_smooth()` .pull-left45[ To add a smoothed line to a plot, use geom_smooth() Main geom_smooth() arguments

 | Arguments| Description| |:------|:----| | method| What function does the line represent?| | col, size, ...| Other plotting aesthetics|
If you add additional plotting aesthetics, they will override the general plotting aesthetics ] .pull-right45[ method = "lm" ```r ggplot(data = mpg, mapping = aes(x = displ, y = hwy, col = class)) + geom_point() + geom_smooth(col = "blue") ```  ] --- ### Smoothed lines with `geom_smooth()` .pull-left45[ To add a smoothed line to a plot, use geom_smooth() Main geom_smooth() arguments

 | Arguments| Description| |:------|:----| | method| What function does the line represent?| | col, size, ...| Other plotting aesthetics|
If you add additional plotting aesthetics, they will override the general plotting aesthetics ] .pull-right45[ method = "lm" ```r ggplot(data = mpg, mapping = aes(x = displ, y = hwy, col = class)) + geom_point() + geom_smooth(col = "blue", method = "lm") # regression ```  ] --- ## Overriding aesthetics - You can include additional aesthetics, like color, shape, and size, in *any* geom. - This will override the *global* aesthetics ```r ggplot(data = mpg, mapping = aes(x = displ, y = hwy, col = class)) + # Global aesthetics geom_point() + geom_smooth(col = "blue") # geom_smooth IGNORES global col aesthetic ```  --- ## Example A: No overriding ```r ggplot(data = mpg, mapping = aes(x = displ, y = hwy, col = class)) + # Global aesthetics geom_point() + # geom_point RESPECTS global col aesthetic (class) geom_smooth() # geom_smooth RESPECTS global col aesthetic (class) ```  --- ## Example B: Override col aesthetic in geom_smooth() ```r ggplot(data = mpg, mapping = aes(x = displ, y = hwy, col = class)) + # Global aesthetics geom_point() + # geom_smooth(col = "blue") # Overrides global col aesthetic (class) ```  --- ## Example C: Override col aesthetic in geom_smooth() & geom_point() ```r ggplot(data = mpg, mapping = aes(x = displ, y = hwy, col = class)) + # Global aesthetics geom_point(col = "pink") + # Overrides global col aesthetic (class) geom_smooth(col = "blue") # Overrides global col aesthetic (class) ```  --- ## Example D: Override col aesthetic in geom_point() ```r ggplot(data = mpg, mapping = aes(x = displ, y = hwy, col = class)) + # Global aesthetics geom_point(col = "pink") + # Overrides global col aesthetic (class) geom_smooth() ```  --- ## What we want ```r ggplot(data = mpg, mapping = aes(x = displ, y = hwy, col = class)) + geom_point() + geom_smooth(col = "blue", # Overrides global col aesthetic (class) method = "lm") # Use lm (linear model) smoothing line ```  --- ### What's next? .pull-left45[ Where we are at. ```r ggplot(data = mpg, mapping = aes(x = displ, y = hwy, col = class)) + geom_point() + geom_smooth(col = "blue", method = "lm") ```  ] .pull-right45[ Our goal

  ] --- ## Add labels with `labs()` .pull-left45[ You can add labels to a plot with the `labs()` function ### `labs()` arguments | Arguments| Description| |:------|:----| | `title`|Main Title| | `subtitle`| Subtitle| | `caption`| Caption below plot| ] .pull-right45[ ```r ggplot(...) + labs(x = "Engine Displ...", y = "Highway miles...", title = "MPG data", subtitle = "Cars with ...", caption = "Source...") ```  ] --- ### What's next? .pull-left6[ Where are are at ```r ggplot(data = mpg, mapping = aes(x = displ, y = hwy, col = class)) + geom_point(size = 3, alpha = .9) + geom_smooth(col = "blue", method = "lm")+ labs(x = "Engine...", y = "Highway ...", title = "MPG data", subtitle = "Cars with...", caption = "Source:...") ```  ] .pull-right35[
 Our goal

  ] --- ## Themes with `theme_XX()` .pull-left45[ A plotting *theme* controls many aspects of its overall look, from the background, to the grid lines, to the label font to the spacing between plot labels and the plotting space. ### Common themes | Themes| |:------| | `theme_bw()`| | `theme_minimal()`| | `theme_classic()`| | `theme_light()`| | `theme_dark()`| - You can easily add a theme to a plot by including `+ theme_XX()` ] .pull-right5[ No theme specified  ```r ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + geom_point() + geom_smooth(method = "lm") ```  ] --- ## Themes with `theme_XX()` .pull-left45[ A plotting *theme* controls many aspects of its overall look, from the background, to the grid lines, to the label font to the spacing between plot labels and the plotting space. ### Common themes | Themes| |:------| | `theme_bw()`| | `theme_minimal()`| | `theme_classic()`| | `theme_light()`| | `theme_dark()`| - You can easily add a theme to a plot by including `+ theme_XX()` ] .pull-right5[ + theme_bw() ```r ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + geom_point() + theme_bw() # Use the black and white theme ```  ] --- ## Themes with `theme_XX()` .pull-left45[ A plotting *theme* controls many aspects of its overall look, from the background, to the grid lines, to the label font to the spacing between plot labels and the plotting space. ### Common themes | Themes| |:------| | `theme_bw()`| | `theme_minimal()`| | `theme_classic()`| | `theme_light()`| | `theme_dark()`| - You can easily add a theme to a plot by including `+ theme_XX()` ] .pull-right5[ + theme_dark() ```r ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + geom_point() + theme_dark() # Use the dark theme ```  ] --- ## Themes with `theme_XX()` .pull-left45[ A plotting *theme* controls many aspects of its overall look, from the background, to the grid lines, to the label font to the spacing between plot labels and the plotting space. ### Common themes | Themes| |:------| | `theme_bw()`| | `theme_minimal()`| | `theme_classic()`| | `theme_light()`| | `theme_dark()`| - You can easily add a theme to a plot by including `+ theme_XX()` ] .pull-right5[ + theme_light() ```r ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + geom_point() + theme_light() # Use the light theme ```  ] --- .pull-left65[ ## Themes You can customise specific elements of themes in the `theme()` function
 ```r ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + geom_point() + theme(plot.background = element_rect(fill = "skyblue"), panel.background = element_rect(fill = "skyblue"), title = element_text(colour = "white", size = 20), axis.title = element_text(colour = "white")) + labs(title = "White Title") ```  ] .pull-right3[

 Look at the theme help menu with ?theme() to see all possible theme adjustments  ] --- ## Set a global theme with theme_set() .pull-left45[
 You can set a global theme with the theme_set() function
 ```r # Set global theme to minimal theme_set(theme_bw()) # All fugure plots will now use theme_bw()! ```
 When you do, all future plots will use that theme! ] .pull-right5[ ```r #Set global theme to theme_dark() theme_set(theme_dark()) ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + geom_point() ```  ] --- ## Final result! ```r ggplot(data = mpg, mapping = aes(x = displ, y = hwy, col = class)) + geom_point() + geom_smooth(col = "blue", method = "lm")+ labs(x = "Engine Displacement in Liters", y = "Highway miles per gallon", title = "MPG data", subtitle = "Cars with higher engine displacement tend to have lower highway mpg", caption = "Source: mpg data in ggplot2") + theme_bw() ```  --- ## Facetting with `facet_wrap()` .pull-left4[
 Facetting = Create different plots for different groups
 To facet plots, use `facet_wrap()`
 ```r # No faceting ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + geom_point() ```  ] .pull-right55[ ```r # With faceting ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + geom_point() + facet_wrap(~ class) # Tilde first! ```  ] --- ## Assigning a ggplot to an object .pull-left35[

 ggplot returns an object of the class "gg"
 You can assign the result of `ggplot` to an object.
 Evaluating the object will show the plot
 You can even edit existing `ggplot` objects
 ] .pull-right6[ ```r # Create myplot myplot <- ggplot(data = mpg, aes(x = cty, y = hwy)) + geom_point() + theme_bw() class(myplot) ``` ``` [1] "gg" "ggplot" ``` ```r myplot # Evaluate myplot ```  ] --- ## Assigning ggplot() to an object .pull-left35[ ```r # Original plot myplot ```  ] .pull-right6[ ```r # Take the existing plot and add elements myplot + facet_wrap(~trans) + theme_dark() ```  ] --- ## Saving plots to image with ggsave() .pull-left5[

 To save plots to a file (e.g.; .jpg, .pdf, .png), use the ggsave() function
 |Argument| Definition| |:-------|:----------| |`filename`|File name| |`plot`|Plotting object| |`device`|File type (e.g.; "pdf", "jpeg", "png")| |`path`|File path to save plot| |`width`|Plot width (inches)| |`height`|Plot height (inches)| ] .pull-right45[ Save ggplot object called myplot to a pdf file
 ```r # Create myplot object myplot <- ggplot(...) # Create "myplot.pdf", from myplot ggsave(filename = "myplot.pdf", plot = myplot, device = "pdf", path = "figures", width = 6, height = 4) ``` ] --- ## So much more Check these links for more in depth ggplot2 guides - ggplot2 main page: http://ggplot2.tidyverse.org/index.html - Wickham's data visualization guide: http://r4ds.had.co.nz/data-visualisation.html  --- # Cheat Sheet! https://www.rstudio.com/wp-content/uploads/2015/03/ggplot2-cheatsheet.pdf  --- ## Plotting Pratical
Link to Plotting practical ---


{% include analytics.html %}
Lucia Montero Sanchis
M.Sc. Communication Systems
Specialization in Data Analytics
{{ content }}


You are logged in if you see this page. Logout
Decorator `django.contrib.auth.decorators.login_required` is applied.
from urldecorators import url, include urlpatterns = [ # ... url(r'^private/', include('example.private.urls'), decorators=['django.contrib.auth.decorators.login_required']), # ... ]


You caught us in the middle of making some improvements, please wait a few moments and try refreshing the page. Sorry for the inconvenience.
If you keep seeing this message after 10 minutes, please contact the web administrator.


|
There seems to be some problem with your subscription.It has not been confimed yet.
|
|
|
|
To confirm your participation, pleaseclick on the link that is sent to youremail address as well.
|
|
Check your Spam Folder if email is not received in your inbox
|
|
You can restart the subscriptionprocess by visiting the website and clicking the subscribe button again.
|
|
|
|
|
|


-
Depending on the characteristic properties, the accessory may be able to update the value of a characteristic. If a characteristic value can be updated, it's text field, radio button, or slider will be editable. Changing this value updates the local value on the accessory, and subsequent reads from the iOS device will retrieve the updated value.
-
Some characteristics may be write-only, in which case the accessory can only read a value sent by the iOS device and does not have the ability to change the value locally.


Enter your device IDs
Device ID
Add
Device Id
Number of Data Points
Clear All
Position Sensors
Enter background image URL:
Update
Save and View Data -->


Control Flow¶
Julia provides a variety of control flow constructs:
- Compound Expressions:
begin
and(;)
. - Conditional Evaluation:
if
-elseif
-else
and?:
(ternary operator). - Short-Circuit Evaluation:
&&
,||
and chained comparisons. - Repeated Evaluation: Loops:
while
andfor
. - Exception Handling:
try
-catch
,error()
andthrow()
. - Tasks (aka Coroutines):
yieldto()
.
The first five control flow mechanisms are standard to high-level
programming languages. Task
s are not so standard: they provide non-local
control flow, making it possible to switch between temporarily-suspended
computations. This is a powerful construct: both exception handling and
cooperative multitasking are implemented in Julia using tasks. Everyday
programming requires no direct usage of tasks, but certain problems can
be solved much more easily by using tasks.
Compound Expressions¶
Sometimes it is convenient to have a single expression which evaluates
several subexpressions in order, returning the value of the last
subexpression as its value. There are two Julia constructs that
accomplish this: begin
blocks and (;)
chains. The value of both
compound expression constructs is that of the last subexpression. Here’s
an example of a begin
block:
julia> z = begin
x = 1
y = 2
x + y
end
3
Since these are fairly small, simple expressions, they could easily be
placed onto a single line, which is where the (;)
chain syntax comes
in handy:
julia> z = (x = 1; y = 2; x + y)
3
This syntax is particularly useful with the terse single-line function
definition form introduced in 함수. Although it
is typical, there is no requirement that begin
blocks be multiline
or that (;)
chains be single-line:
julia> begin x = 1; y = 2; x + y end
3
julia> (x = 1;
y = 2;
x + y)
3
Conditional Evaluation¶
Conditional evaluation allows portions of code to be evaluated or not
evaluated depending on the value of a boolean expression. Here is the
anatomy of the if
-elseif
-else
conditional syntax:
if x < y
println("x is less than y")
elseif x > y
println("x is greater than y")
else
println("x is equal to y")
end
If the condition expression x < y
is true
, then the corresponding block
is evaluated; otherwise the condition expression x > y
is evaluated, and if
it is true
, the corresponding block is evaluated; if neither expression is
true, the else
block is evaluated. Here it is in action:
julia> function test(x, y)
if x < y
println("x is less than y")
elseif x > y
println("x is greater than y")
else
println("x is equal to y")
end
end
test (generic function with 1 method)
julia> test(1, 2)
x is less than y
julia> test(2, 1)
x is greater than y
julia> test(1, 1)
x is equal to y
The elseif
and else
blocks are optional, and as many elseif
blocks as desired can be used. The condition expressions in the
if
-elseif
-else
construct are evaluated until the first one
evaluates to true
, after which the associated block is evaluated,
and no further condition expressions or blocks are evaluated.
if
blocks are “leaky”, i.e. they do not introduce a local scope.
This means that new variables defined inside the ìf
clauses can
be used after the if
block, even if they weren’t defined before.
So, we could have defined the test
function above as
julia> function test(x,y)
if x < y
relation = "less than"
elseif x == y
relation = "equal to"
else
relation = "greater than"
end
println("x is ", relation, " y.")
end
test (generic function with 1 method)
The variable relation
is declared inside the if
block, but used
outside. However, when depending on this behavior, make sure all possible
code paths define a value for the variable. The following change to
the above function results in a runtime error
julia> function test(x,y)
if x < y
relation = "less than"
elseif x == y
relation = "equal to"
end
println("x is ", relation, " y.")
end
test (generic function with 1 method)
julia> test(1,2)
x is less than y.
julia> test(2,1)
ERROR: UndefVarError: relation not defined
in test(::Int64, ::Int64) at ./none:7
...
if
blocks also return a value, which may seem unintuitive to users
coming from many other languages. This value is simply the return value
of the last executed statement in the branch that was chosen, so
julia> x = 3
3
julia> if x > 0
"positive!"
else
"negative..."
end
"positive!"
Note that very short conditional statements (one-liners) are frequently expressed using Short-Circuit Evaluation in Julia, as outlined in the next section.
Unlike C, MATLAB, Perl, Python, and Ruby — but like Java, and a few
other stricter, typed languages — it is an error if the value of a
conditional expression is anything but true
or false
:
julia> if 1
println("true")
end
ERROR: TypeError: non-boolean (Int64) used in boolean context
...
This error indicates that the conditional was of the wrong type:
Int64
rather than the required Bool
.
The so-called “ternary operator”, ?:
, is closely related to the
if
-elseif
-else
syntax, but is used where a conditional
choice between single expression values is required, as opposed to
conditional execution of longer blocks of code. It gets its name from
being the only operator in most languages taking three operands:
a ? b : c
The expression a
, before the ?
, is a condition expression, and
the ternary operation evaluates the expression b
, before the :
,
if the condition a
is true
or the expression c
, after the
:
, if it is false
.
The easiest way to understand this behavior is to see an example. In the
previous example, the println
call is shared by all three branches:
the only real choice is which literal string to print. This could be
written more concisely using the ternary operator. For the sake of
clarity, let’s try a two-way version first:
julia> x = 1; y = 2;
julia> println(x < y ? "less than" : "not less than")
less than
julia> x = 1; y = 0;
julia> println(x < y ? "less than" : "not less than")
not less than
If the expression x < y
is true, the entire ternary operator
expression evaluates to the string "less than"
and otherwise it
evaluates to the string "not less than"
. The original three-way
example requires chaining multiple uses of the ternary operator
together:
julia> test(x, y) = println(x < y ? "x is less than y" :
x > y ? "x is greater than y" : "x is equal to y")
test (generic function with 1 method)
julia> test(1, 2)
x is less than y
julia> test(2, 1)
x is greater than y
julia> test(1, 1)
x is equal to y
To facilitate chaining, the operator associates from right to left.
It is significant that like if
-elseif
-else
, the expressions
before and after the :
are only evaluated if the condition
expression evaluates to true
or false
, respectively:
julia> v(x) = (println(x); x)
v (generic function with 1 method)
julia> 1 < 2 ? v("yes") : v("no")
yes
"yes"
julia> 1 > 2 ? v("yes") : v("no")
no
"no"
Short-Circuit Evaluation¶
Short-circuit evaluation is quite similar to conditional evaluation. The
behavior is found in most imperative programming languages having the
&&
and ||
boolean operators: in a series of boolean expressions
connected by these operators, only the minimum number of expressions are
evaluated as are necessary to determine the final boolean value of the
entire chain. Explicitly, this means that:
- In the expression
a && b
, the subexpressionb
is only evaluated ifa
evaluates totrue
. - In the expression
a || b
, the subexpressionb
is only evaluated ifa
evaluates tofalse
.
The reasoning is that a && b
must be false
if a
is
false
, regardless of the value of b
, and likewise, the value of
a || b
must be true if a
is true
, regardless of the value of
b
. Both &&
and ||
associate to the right, but &&
has
higher precedence than ||
does. It’s easy to experiment with
this behavior:
julia> t(x) = (println(x); true)
t (generic function with 1 method)
julia> f(x) = (println(x); false)
f (generic function with 1 method)
julia> t(1) && t(2)
1
2
true
julia> t(1) && f(2)
1
2
false
julia> f(1) && t(2)
1
false
julia> f(1) && f(2)
1
false
julia> t(1) || t(2)
1
true
julia> t(1) || f(2)
1
true
julia> f(1) || t(2)
1
2
true
julia> f(1) || f(2)
1
2
false
You can easily experiment in the same way with the associativity and
precedence of various combinations of &&
and ||
operators.
This behavior is frequently used in Julia to form an alternative to very short
if
statements. Instead of if <cond> <statement> end
, one can write
<cond> && <statement>
(which could be read as: <cond> and then <statement>).
Similarly, instead of if ! <cond> <statement> end
, one can write
<cond> || <statement>
(which could be read as: <cond> or else <statement>).
For example, a recursive factorial routine could be defined like this:
julia> function fact(n::Int)
n >= 0 || error("n must be non-negative")
n == 0 && return 1
n * fact(n-1)
end
fact (generic function with 1 method)
julia> fact(5)
120
julia> fact(0)
1
julia> fact(-1)
ERROR: n must be non-negative
in fact(::Int64) at ./none:2
...
Boolean operations without short-circuit evaluation can be done with the
bitwise boolean operators introduced in 수학 연산들과 기본적인 함수들:
&
and |
. These are normal functions, which happen to support
infix operator syntax, but always evaluate their arguments:
julia> f(1) & t(2)
1
2
false
julia> t(1) | t(2)
1
2
true
Just like condition expressions used in if
, elseif
or the
ternary operator, the operands of &&
or ||
must be boolean
values (true
or false
). Using a non-boolean value anywhere
except for the last entry in a conditional chain is an error:
julia> 1 && true
ERROR: TypeError: non-boolean (Int64) used in boolean context
...
On the other hand, any type of expression can be used at the end of a conditional chain. It will be evaluated and returned depending on the preceding conditionals:
julia> true && (x = rand(2,2))
2×2 Array{Float64,2}:
0.768448 0.673959
0.940515 0.395453
julia> false && (x = rand(2,2))
false
Repeated Evaluation: Loops¶
There are two constructs for repeated evaluation of expressions: the
while
loop and the for
loop. Here is an example of a while
loop:
julia> i = 1;
julia> while i <= 5
println(i)
i += 1
end
1
2
3
4
5
The while
loop evaluates the condition expression (i <= 5
in this
case), and as long it remains true
, keeps also evaluating the body
of the while
loop. If the condition expression is false
when the
while
loop is first reached, the body is never evaluated.
The for
loop makes common repeated evaluation idioms easier to
write. Since counting up and down like the above while
loop does is
so common, it can be expressed more concisely with a for
loop:
julia> for i = 1:5
println(i)
end
1
2
3
4
5
Here the 1:5
is a Range
object, representing the sequence of
numbers 1, 2, 3, 4, 5. The for
loop iterates through these values,
assigning each one in turn to the variable i
. One rather important
distinction between the previous while
loop form and the for
loop form is the scope during which the variable is visible. If the
variable i
has not been introduced in an other scope, in the for
loop form, it is visible only inside of the for
loop, and not
afterwards. You’ll either need a new interactive session instance or a
different variable name to test this:
julia> for j = 1:5
println(j)
end
1
2
3
4
5
julia> j
ERROR: UndefVarError: j not defined
...
See Scope of Variables for a detailed explanation of variable scope and how it works in Julia.
In general, the for
loop construct can iterate over any container.
In these cases, the alternative (but fully equivalent) keyword in
or ∈
is typically used instead of =
, since it makes the code read more
clearly:
julia> for i in [1,4,0]
println(i)
end
1
4
0
julia> for s ∈ ["foo","bar","baz"]
println(s)
end
foo
bar
baz
Various types of iterable containers will be introduced and discussed in later sections of the manual (see, e.g., Multi-dimensional Arrays).
It is sometimes convenient to terminate the repetition of a while
before the test condition is falsified or stop iterating in a for
loop before the end of the iterable object is reached. This can be
accomplished with the break
keyword:
julia> i = 1;
julia> while true
println(i)
if i >= 5
break
end
i += 1
end
1
2
3
4
5
julia> for i = 1:1000
println(i)
if i >= 5
break
end
end
1
2
3
4
5
The above while
loop would never terminate on its own, and the
for
loop would iterate up to 1000. These loops are both exited early
by using the break
keyword.
In other circumstances, it is handy to be able to stop an iteration and
move on to the next one immediately. The continue
keyword
accomplishes this:
julia> for i = 1:10
if i % 3 != 0
continue
end
println(i)
end
3
6
9
This is a somewhat contrived example since we could produce the same
behavior more clearly by negating the condition and placing the
println
call inside the if
block. In realistic usage there is
more code to be evaluated after the continue
, and often there are
multiple points from which one calls continue
.
Multiple nested for
loops can be combined into a single outer loop,
forming the cartesian product of its iterables:
julia> for i = 1:2, j = 3:4
println((i, j))
end
(1,3)
(1,4)
(2,3)
(2,4)
A break
statement inside such a loop exits the entire nest of loops,
not just the inner one.
Exception Handling¶
When an unexpected condition occurs, a function may be unable to return a reasonable value to its caller. In such cases, it may be best for the exceptional condition to either terminate the program, printing a diagnostic error message, or if the programmer has provided code to handle such exceptional circumstances, allow that code to take the appropriate action.
Built-in Exception
s¶
Exception
s are thrown when an unexpected condition has occurred. The
built-in Exception
s listed below all interrupt the normal flow of control.
Exception |
|---|
ArgumentError |
BoundsError |
CompositeException |
DivideError |
DomainError |
EOFError |
ErrorException |
InexactError |
InitError |
InterruptException |
InvalidStateException |
KeyError |
LoadError |
OutOfMemoryError |
ReadOnlyMemoryError |
RemoteException |
MethodError |
OverflowError |
ParseError |
SystemError |
TypeError |
UndefRefError |
UndefVarError |
UnicodeError |
For example, the sqrt()
function throws a DomainError
if applied to a
negative real value:
julia> sqrt(-1)
ERROR: DomainError:
sqrt will only return a complex result if called with a complex argument. Try sqrt(complex(x)).
in sqrt(::Int64) at ./math.jl:185
...
You may define your own exceptions in the following way:
julia> type MyCustomException <: Exception end
The throw()
function¶
Exceptions can be created explicitly with throw()
. For example, a function
defined only for nonnegative numbers could be written to throw()
a DomainError
if the argument is negative:
julia> f(x) = x>=0 ? exp(-x) : throw(DomainError())
f (generic function with 1 method)
julia> f(1)
0.36787944117144233
julia> f(-1)
ERROR: DomainError:
in f(::Int64) at ./none:1
...
Note that DomainError
without parentheses is not an exception, but a type of
exception. It needs to be called to obtain an Exception
object:
julia> typeof(DomainError()) <: Exception
true
julia> typeof(DomainError) <: Exception
false
Additionally, some exception types take one or more arguments that are used for error reporting:
julia> throw(UndefVarError(:x))
ERROR: UndefVarError: x not defined
...
This mechanism can be implemented easily by custom exception types following
the way UndefVarError
is written:
julia> type MyUndefVarError <: Exception
var::Symbol
end
julia> Base.showerror(io::IO, e::MyUndefVarError) = print(io, e.var, " not defined");
Errors¶
The error()
function is used to produce an ErrorException
that
interrupts the normal flow of control.
Suppose we want to stop execution immediately if the square root of a
negative number is taken. To do this, we can define a fussy version of
the sqrt()
function that raises an error if its argument is negative:
julia> fussy_sqrt(x) = x >= 0 ? sqrt(x) : error("negative x not allowed")
fussy_sqrt (generic function with 1 method)
julia> fussy_sqrt(2)
1.4142135623730951
julia> fussy_sqrt(-1)
ERROR: negative x not allowed
in fussy_sqrt(::Int64) at ./none:1
...
If fussy_sqrt
is called with a negative value from another function,
instead of trying to continue execution of the calling function, it
returns immediately, displaying the error message in the interactive
session:
julia> function verbose_fussy_sqrt(x)
println("before fussy_sqrt")
r = fussy_sqrt(x)
println("after fussy_sqrt")
return r
end
verbose_fussy_sqrt (generic function with 1 method)
julia> verbose_fussy_sqrt(2)
before fussy_sqrt
after fussy_sqrt
1.4142135623730951
julia> verbose_fussy_sqrt(-1)
before fussy_sqrt
ERROR: negative x not allowed
in fussy_sqrt at ./none:1 [inlined]
in verbose_fussy_sqrt(::Int64) at ./none:3
...
Warnings and informational messages¶
Julia also provides other functions that write messages to the standard error
I/O, but do not throw any Exception
s and hence do not interrupt
execution:
julia> info("Hi"); 1+1
INFO: Hi
2
julia> warn("Hi"); 1+1
WARNING: Hi
2
julia> error("Hi"); 1+1
ERROR: Hi
in error(::String) at ./error.jl:21
...
The try/catch
statement¶
The try/catch
statement allows for Exception
s to be tested for. For
example, a customized square root function can be written to automatically
call either the real or complex square root method on demand using
Exception
s :
julia> f(x) = try
sqrt(x)
catch
sqrt(complex(x, 0))
end
f (generic function with 1 method)
julia> f(1)
1.0
julia> f(-1)
0.0 + 1.0im
It is important to note that in real code computing this function, one would
compare x
to zero instead of catching an exception. The exception is much
slower than simply comparing and branching.
try/catch
statements also allow the Exception
to be saved in a
variable. In this contrived example, the following example calculates the
square root of the second element of x
if x
is indexable, otherwise
assumes x
is a real number and returns its square root:
julia> sqrt_second(x) = try
sqrt(x[2])
catch y
if isa(y, DomainError)
sqrt(complex(x[2], 0))
elseif isa(y, BoundsError)
sqrt(x)
end
end
sqrt_second (generic function with 1 method)
julia> sqrt_second([1 4])
2.0
julia> sqrt_second([1 -4])
0.0 + 2.0im
julia> sqrt_second(9)
3.0
julia> sqrt_second(-9)
ERROR: DomainError:
in sqrt_second(::Int64) at ./none:7
...
Note that the symbol following catch
will always be interpreted as a
name for the exception, so care is needed when writing try/catch
expressions
on a single line. The following code will not work to return the value of x
in case of an error:
try bad() catch x end
Instead, use a semicolon or insert a line break after catch
:
try bad() catch; x end
try bad()
catch
x
end
The catch
clause is not strictly necessary; when omitted, the default
return value is nothing
.
julia> try error() end #Returns nothing
The power of the try/catch
construct lies in the ability to unwind a deeply
nested computation immediately to a much higher level in the stack of calling
functions. There are situations where no error has occurred, but the ability to
unwind the stack and pass a value to a higher level is desirable. Julia
provides the rethrow()
, backtrace()
and catch_backtrace()
functions for
more advanced error handling.
finally Clauses¶
In code that performs state changes or uses resources like files, there is
typically clean-up work (such as closing files) that needs to be done when the
code is finished. Exceptions potentially complicate this task, since they can
cause a block of code to exit before reaching its normal end. The finally
keyword provides a way to run some code when a given block of code exits,
regardless of how it exits.
For example, here is how we can guarantee that an opened file is closed:
f = open("file")
try
# operate on file f
finally
close(f)
end
When control leaves the try
block (for example due to a return
, or
just finishing normally), close(f)
will be executed. If
the try
block exits due to an exception, the exception will continue
propagating. A catch
block may be combined with try
and finally
as well. In this case the finally
block will run after catch
has
handled the error.
Tasks (aka Coroutines)¶
Tasks are a control flow feature that allows computations to be suspended and resumed in a flexible manner. This feature is sometimes called by other names, such as symmetric coroutines, lightweight threads, cooperative multitasking, or one-shot continuations.
When a piece of computing work (in practice, executing a particular
function) is designated as a Task
, it becomes possible to interrupt
it by switching to another Task
. The original Task
can later be
resumed, at which point it will pick up right where it left off. At
first, this may seem similar to a function call. However there are two
key differences. First, switching tasks does not use any space, so any
number of task switches can occur without consuming the call stack.
Second, switching among tasks can occur in any order, unlike function calls,
where the called function must finish executing before control returns
to the calling function.
This kind of control flow can make it much easier to solve certain problems. In some problems, the various pieces of required work are not naturally related by function calls; there is no obvious “caller” or “callee” among the jobs that need to be done. An example is the producer-consumer problem, where one complex procedure is generating values and another complex procedure is consuming them. The consumer cannot simply call a producer function to get a value, because the producer may have more values to generate and so might not yet be ready to return. With tasks, the producer and consumer can both run as long as they need to, passing values back and forth as necessary.
Julia provides the functions produce()
and consume()
for solving
this problem. A producer is a function that calls produce()
on each
value it needs to produce:
julia> function producer()
produce("start")
for n=1:4
produce(2n)
end
produce("stop")
end;
To consume values, first the producer is wrapped in a Task
,
then consume()
is called repeatedly on that object:
julia> p = Task(producer);
julia> consume(p)
"start"
julia> consume(p)
2
julia> consume(p)
4
julia> consume(p)
6
julia> consume(p)
8
julia> consume(p)
"stop"
One way to think of this behavior is that producer
was able to
return multiple times. Between calls to produce()
, the producer’s
execution is suspended and the consumer has control.
A Task can be used as an iterable object in a for
loop, in which
case the loop variable takes on all the produced values:
julia> for x in Task(producer)
println(x)
end
start
2
4
6
8
stop
Note that the Task()
constructor expects a 0-argument function. A
common pattern is for the producer to be parameterized, in which case a
partial function application is needed to create a 0-argument anonymous
function. This can be done either
directly or by use of a convenience macro:
function mytask(myarg)
...
end
taskHdl = Task(() -> mytask(7))
# or, equivalently
taskHdl = @task mytask(7)
produce()
and consume()
do not launch threads that can run on separate CPUs.
True kernel threads are discussed under the topic of Parallel Computing.
Core task operations¶
While produce()
and consume()
illustrate the essential nature of tasks, they
are actually implemented as library functions using a more primitive function,
yieldto()
. yieldto(task,value)
suspends the current task, switches
to the specified task
, and causes that task’s last yieldto()
call to return
the specified value
. Notice that yieldto()
is the only operation required
to use task-style control flow; instead of calling and returning we are always
just switching to a different task. This is why this feature is also called
“symmetric coroutines”; each task is switched to and from using the same mechanism.
yieldto()
is powerful, but most uses of tasks do not invoke it directly.
Consider why this might be. If you switch away from the current task, you will
probably want to switch back to it at some point, but knowing when to switch
back, and knowing which task has the responsibility of switching back, can
require considerable coordination. For example, produce()
needs to maintain
some state to remember who the consumer is. Not needing to manually keep track
of the consuming task is what makes produce()
easier to use than yieldto()
.
In addition to yieldto()
, a few other basic functions are needed to use tasks
effectively.
current_task()
gets a reference to the currently-running task.istaskdone()
queries whether a task has exited.istaskstarted()
queries whether a task has run yet.task_local_storage()
manipulates a key-value store specific to the current task.
Tasks and events¶
Most task switches occur as a result of waiting for events such as I/O requests, and are performed by a scheduler included in the standard library. The scheduler maintains a queue of runnable tasks, and executes an event loop that restarts tasks based on external events such as message arrival.
The basic function for waiting for an event is wait()
. Several objects
implement wait()
; for example, given a Process
object, wait()
will
wait for it to exit. wait()
is often implicit; for example, a wait()
can happen inside a call to read()
to wait for data to be available.
In all of these cases, wait()
ultimately operates on a Condition
object, which is in charge of queueing and restarting tasks. When a task
calls wait()
on a Condition
, the task is marked as non-runnable, added
to the condition’s queue, and switches to the scheduler. The scheduler will
then pick another task to run, or block waiting for external events.
If all goes well, eventually an event handler will call notify()
on the
condition, which causes tasks waiting for that condition to become runnable
again.
A task created explicitly by calling Task
is initially not known to the
scheduler. This allows you to manage tasks manually using yieldto()
if
you wish. However, when such a task waits for an event, it still gets restarted
automatically when the event happens, as you would expect. It is also
possible to make the scheduler run a task whenever it can, without necessarily
waiting for any events. This is done by calling schedule()
, or using
the @schedule
or @async
macros (see Parallel Computing for
more details).
Task states¶
Tasks have a state
field that describes their execution status. A task
state is one of the following symbols:
| Symbol | Meaning |
|---|---|
:runnable |
Currently running, or available to be switched to |
:waiting |
Blocked waiting for a specific event |
:queued |
In the scheduler’s run queue about to be restarted |
:done |
Successfully finished executing |
:failed |
Finished with an uncaught exception |


Chapter 16
Strings
A string is a very common object in Zen. You have used strings throughout this manual. You have seen how to use string literals, how to concatenate strings, and how to compare strings. However, strings are much more powerful and support a wide variety of operations.
In this chapter, you will learn more about strings.
+++ title = “Understanding Strings” weight = 1 +++
In Zen, strings are not primitive reference types. Strings are implemented by the
String
class defined in the zen.core
package. All strings are objects and Zen
treats strings specially.
A string is a sequence of characters. You can create a string by enclosing your text in single quotes. The character sequence along with the single quotes form a string literal.
Unlike many other programming languages, string are not arrays of characters.
Internally the String
class stores the characters in an array, a detail which
you can safely ignore. But you always need to perceive strings as objects and
not arrays.
So far you have seen only one way to create a string object: to use the string
literal. However, the String
class exposes many constructors, which allow
you to create strings in many ways.
You can perform various operations with strings, such as comparing two strings, searching for substrings, concatenating two strings, and so on. However, you cannot modify them because string objects are immutable. In other words, once a string object is created, you cannot change its characters. You can only derive a new string which is a modified version of the original string. At first, this may seem to be a serious restriction. However, immutable strings make your life easier. You can still perform all types of string operations. Immutable strings are more efficient than mutable strings.
Zen provides other mechanisms which allow you to derive modified versions of a string. Each time you derive a new version of the string, you are creating a new string object. The original string is always left as it is.
If you have to make many changes to a string, deriving a new string for each
change is not efficient. For such situtations, Zen provides the StringBuilder
class, which internally represent strings as arrays. So whatever changes you make
will be quick and efficient. Once you are satisfied with the changes, these
classes allow you to derive an immutable string. After which, you can use the
string as usual.
The String and StringBuilder classes are defined in the zen.core
and zen.text
packages, respectively. Therefore, all these classes are available to your programs
automatically. All the three classes extend the CharacterSequence
abstract class,
which means most operations you find in strings are found in the other class, too.
Before we continue, here is a summary of strings.
- Strings can include escape sequences. An escape sequence allows you to represent a special character which you would not be able to type with your keyboard. It is written with a backward slash followed by a letter.
Here is the list of all the escape sequences availablen in Zen.
| Escape Sequence | Description |
|---|---|
| \n | Newline |
| \t | Tab |
| \b | Backspace |
| \r | Carriage Return |
| \f | Form feed |
| \’ | Apostrophe |
| \” | Quotation mark |
| \\ | Backslash |
-
Strings are objects. You enclose a string literal in single quotes. A string can contain zero or more characters, even if a string contains a single
-
Strings are an important part of programming languages, therefore Zen treats strings specially. In fact, strings support many special syntax. For example, string objects are created from string literals. However, you can use the constructors of the String class for more flexbility. You will learn about these constructors in the next lecture.
-
You can combine, or concatenate, strings using the concatenation operator (
+
). You can combine strings with other values, in which case Zen automatically converts the value to a string for you. In the case of objects, thetoString()
function is first invoked to derive a string representation.Here is an example of the concatenation operator.
var firstPart = 'Hello, '
var secondPart = 'world!'
var message = firstPart + secondPart
-
Zen offers a wrapper class for each primitive type defined by the Zen Virtual Machine. These wrapper classes allow you to convert a string to a corresponding value. You can do this with the
parse()
function these classes expose.Here is an example of how you can convert a string to an integer.
// StringToInteger.zen
function main(...arguments)
var text = '2019'
var year = Integer.parse(text)
printf('This is the year %d. After 11 years, it will be the year %d.\n', year + 11)
This example converts the string which contains '2019'
to its equivalent
integer value, which is 2019
. However, if you specify an invalid text these
functions throw NumberFormatException
.
-
Unlike other programming languages, Zen does not support characters inherently. However, integer values can be treated as characters and additional support is provided through the
Character
class.+++ title = “Constructors of the String Class” weight = 2 +++
The String
class exposes many constructors. You will learn about a few of
these constructors in this section. Please refer the Zen API documentation for
more information.
Creating Empty Strings
You can create an empty string by calling the default constructor. An empty string basically contains no characters.
Here is an example.
var emtpyString = new String()
Creating Strings From Array of Characters
The String
class implements a constructor which accepts an array of characters.
This allows you to create a string from an array of characters.
function new(sequence)
Here is an example which demonstrates how you can create strings using arrays.
var sequence = arrayEx(String, 'F', 'e', 'b', 'r', 'u', 'a', 'r', 'y' )
var string = new String(sequence)
This creates a string that holds the text 'February'
.
You can further specify a range within the array you want the constructor to copy using this constructor.
function new(sequence, startIndex, count)
Here, the startIndex
indicates the index from where the characters should be
copied. It is inclusive, which means the string at the start index is also
included. The count parameter indicates the number of characters to copy,
beginning the copy at the start index.
The following example demonstrates this constructor.
var sequence = arrayEx(String, 'F', 'e', 'b', 'r', 'u', 'a', 'r', 'y')
var string = new String(sequence, 3, 2)
This creates a string which represents 'ru'
. Remember indexes in Zen always
begin at 0
, therefore, 3
indicates the fourth character.
Cloning Strings
You can create a copy of the string object using the clone()
function.
Here is an example.
// StringCopy.zen
function main(...arguments)
var string1 = 'Hello'
var string2 = string1.clone()
print(string1 is string2)
print(string1 == string2)
The first string contains the text 'Hello'
. We create another copy of this string.
Since the is
operator tests if both the variables contain the same reference,
the first print statement prints false. In other words, the variables string1
and string2
hold two different references. However, they hold logically equal
objects because they both contain the same text. To prove that they contain the
same text, we use the ==
operator, which invokes the equals()
function. This
is why the second print statement prints true
.
There are many other constructors implemented in the String
class. We encourage
you to learn more about these constructors from the Zen API documentation.
+++ title = “Determining the Size of Strings” weight = 3 +++
You can determine the size of a string using the immutable size
property.
The size of a string is basically the number of code points it contains.
Here is an example which prints the size of a string.
// StringSize.zen
function main(...arguments)
var name = 'Shazam'
printf('The size of "%s" is %d.\n', name.size)
The example above produces the following output:
The size of "Shazam" is 6.
The size of a string is an important value when you want to manipulate strings.
+++ title = “Comparing Strings” weight = 4 +++
String Equality
You can compare two strings for equality using the equality operator (==
).
The behavior of the equality operator is overridden in the equals()
function,
which means you can use it to compare two strings for equality, too.
The declaration of the equals
function is shown here.
function equals(other)
It returns true
if both the strings contain the same characters in the same
order; false
otherwise. You need to remember that this function is case sensistive.
For example, if you compare 'Batman'
and 'batman'
for equality, it would
return false
.
Here is an example which demonstrates how you can compare two strings for equality.
// StringEquality.zen
function main(...arguments)
var string1 = 'Joker'
var string2 = 'Harley Quinn'
if string1.equals(string2)
printf('"%s" is equal to "%s"!\n', string1, string2)
else
printf('"%s" is not equal to "%s"!\n', string1, string2)
You can compare two strings for equality without considering case. For this, you need to invoke the overloaded version of the equals() function.
function equals(other, ignoreCase)
It returns true
if both the strings contain the same characters in the same
order; false
otherwise. You need to remember that this function is case
insensistive. For example, if you compare 'Camel'
and 'camel'
for equality,
it would return true
.
Here is an example which demonstrates how you can compare two strings for equality.
// StringEquality2.zen
function main(...arguments)
var string1 = 'Poison Ivy'
var string2 = 'poison ivy'
if string1.equals(string2, true)
printf('"%s" is equal to "%s"!\n', string1, string2)
else
printf('"%s" is not equal to "%s"!\n', string1, string2)
Comparing String Regions
You can compare a region inside your string with the region of another string.
You need to invoke the regionMatches()
function for this.
Here is the declaration of the regionMatches()
function.
function regionMatches(startIndex, other, otherStartIndex, count)
The startIndex
specifies the index at which the region begins for the string
object against which the function is invoked.
other
represents the other string to compare. The otherIndex
indicates the
index at which the region begins for the other string.
The count
parameter indicates the number of characters in both the regions.
You need to carefully specify this parameter.
You can force regionMatches()
function to ignore case. For this invoke the
overloaded version of the regionMatches()
.
function regionMatches(startIndex, other, otherStartIndex, count, ignoreCase)
The ignoreCase
boolean parameter indicates whether the function should ignore
case when comparing, or not.
Prefixes and Suffixes
You can determine if a string starts with a substring using the startsWith()
function. It returns true
if a string starts with the specified substring;
false
otherwise.
Here is the declaration of the startsWith()
function.
function startsWith(sequence)
Further, you can specify from which index startsWith()
begins comparing.
An overloaded version of the startsWith()
function accepts the starting index.
Here is the declaration of this function.
function startsWith(sequence, startIndex)
Here, the startIndex
specifies the index applies to the string object against
which the function is invoked. It indicates the index from where the comparison is
started.
Similarly, you can determine if a string ends with a substring using the endsWith()
function. It returns false
if a string ends with the specified substring; false
otherwise.
Here is the declaration of the endsWith()
function.
function endsWith(sequence)
Here is an example which demonstrates these functions.
function main(...arguments)
var superhero = 'Swamp Thing'
var r1 = superhero.startsWith('Swam')
var r2 = superhero.endsWith('ing')
var r3 = superhero.startsWith('Thing', 5)
printf('"%s" starts with "Swam": %z\n', superhero, r1)
printf('"%s" ends with "ing": %z\n', superhero, r2)
printf('"%s" starts with "Thing" after 5 characters: %z\n', superhero, r3)
This example produces the following output.
"Swamp Thing" starts with "Swam": true
"Swamp Thing" ends with "ing": true
"Swamp Thing" starts with "Thing" after 5 characters: true
Comparing Strings
Imagine you are sorting an array of strings. How can you determine whether one
string is greater than the other? So far you have learnt about functions that only
help you determine whether they are identical. In order to compare strings
for relativity, you need to use the compare()
function.
The compare()
function compares two strings lexicographically, which means
a A is lesser B, B is lesser than C and so on. For example, A is lesser than Z
and Y is greater than M. In this logic, lowercase letters are always greater
than uppercase letters.
The declaration of the compare()
function is shown here.
function compare(other)
-
It returns a negative number if the current string object is lesser than the specified string.
-
It returns a positive number if the current string object is greater than the specified string.
-
It returns zero when both the strings are equal.
Here is an example, which determines if a string is greater than the other.
// YatchVsDragon.zen
function main(...arguments)
var yatch = 'Yatch'
var dragon = 'Dragon'
if yatch.compare(dragon) > 0
print('Yatch is greater than Dragon.')
else if yatch.compare(dragon) < 0
print('Yatch is lesser than Dragon.')
else
print('Yatch is equal to Dragon.')
This program generate the following output.
Yatch is greater than Dragon.
As mentioned previously, the compare()
function is case sensitive. For case
insensistive comparison you need to invoke the overloaded version of the compare()
function which accepts a Boolean flag indicating whether the function has to
ignore case or not.
The declaration of the overloaded version of the compare()
function is shown
below.
function compare(other, ignoreCase)
+++ title = ‘Extracting Characters From Strings’ weight = 5 +++
You can extract characters from strings in a number of ways. We discuss about each technique in this section.
Internally, strings store characters in an array. The String
class overrides
the subscript operator, which allows you to access characters in a string as if
it were an array. Many functions in the String
class require indexes to operate.
Just like array, string indexes are zero based. So it would help you to understand
strings better if you think of them as arrays.
You can extract a single character from a string using the getCharacter()
function.
It accepts an index of the character you want to retrieve. You cannot specify
negative values. It throws a InvalidStringIndexException
if the index is invalid.
Here is the declaration of the getCharacter()
function.
@Operator symbol='[]'
function getCharacter(index)
Here is an example.
// AccessingCharacter.zen
function main(...arguments)
var color = 'Neon'
var c = color.getCharacter(2)
print(c)
This snipet prints the following output.
o
You can retrieve a range of characters at a time using the getCharacters()
function.
Here is the declaration of the getCharacters()
function.
function getCharacters(startIndex, stopIndex, destination, destinationIndex)
Here, the startIndex
specifies the index from which the copying begins. It is
inclusive.
The stopIndex
specifies the index at which the copying ends. This index is exclusive,
which means the character at this index is not copied.
The characters are copied to the destination
array you specify. The characters
are copied into the destination array beginning at the index specified by
destinationIndex
. You need to make sure that the destination array is large
enough to store the range of characters.
Here is an example which copies a range of characters.
// CharacterExtraction.zen
function main(...arguments)
var message = 'How you doin?'
var startIndex = 4
var stopIndex = 7
var destination = new Array(Character, 3)
message.getCharacters(startIndex, stopIndex, destination, 0)
var message2 = new String(destination)
print(message2)
This example prints the following.
you
If you want to convert all the characters in your string into a character array,
invoke the toCharacterArray()
function. It returns an array of characters from
your string.
The declaration of the toCharacterArray()
function is shown here.
function toCharacterArray()
You can use the getCharacters()
function to perform the same operation, except
getCharacters()
makes you write more code.
Extracting Substrings
The substring()
function allows you to extract a region of your string, usually
referred as substring.
The declaration of this function is shown here.
function substring(index)
Here, the index indicates the index from which the substring is extracted. The substring begins from the specified index and extends to the end of the string.
Here is an example of the substring()
function.
// SubstringExtraction.zen
function main(...arguments)
var lastName = 'Nikola Tesla'.substring(7)
printf('%s was one of the greatest inventors to ever live!\n', lastName)
This example prints the following output.
Tesla was one of the greatest inventors to ever live!
An overloaded version of the substring()
function allows you to extract a
range of characters from the string.
Here is the declaration of the substring()
function.
function substring(startIndex, stopIndex)
Here the startIndex
specifies the start index of the substring and the
stopIndex
specifies the end index of the substring. The startIndex
is
inclusive, whereas, the stopIndex
is exclusive.
Here is an example of the overloaded version of the substring()
function.
var substring = 'Nikola Tesla'.substring(2, 6)
println(substring)
This example prints the following output.
kola


Woman shares simple tip to tackle bathroom mould - and there's not a scrubbing brush in sight
A woman has revealed a miraculous way to tacky mouldy bathroom tiles
by Courtney PochinTired of mouldy bathroom tiles which take hours to clean?
Trying to get rid of it can be incredibly tricky, but one woman claims to have found a solution.
In a post on a cleaning tips and tricks Facebook group, an unnamed woman revealed she'd found a simple hack for removing mould without doing an intense scrubbing - and it only cost around £2 to do.
The Mirror reports that the woman initially posted a photo of her mouldy grouting on the group, asking fellow members for suggestions on how to get them looking good as new.
Many people responded to her post, sharing ideas, including using toilet bowl cleaner and just re-sealing the tiles.
After trying a few of the hacks out, she finally found one that really did the trick, and all she needed were cotton wool and bleach to do it.
The woman claims she soaked a pieces of the cotton wool in the cleaning product and packed them all around the edges of the tiles.
The cotton wool was left on the tiles overnight and by the morning, the difference was incredible.
She re-shared her original photo as well as a new one showing the results of the cleaning trick.
"Thank you to everyone who has commented," she said. "I used cotton wool and bleach and have attached photos of the results. Wow!"
Dozens of people liked her post, with one person commented: "This is amazing!"


Enter your Infura ID that will connect you to the Ethereum Blockchain
You need to provide a valid Infura Project ID
{% end %} {% block question %}
Raiden is an off chain scaling solution for the Ethereum Blockchain.
The Raiden Wizard as well as Raiden need to connect to an Ethereum
node.
The
Infura API suite
provides instant access over HTTPS and WebSockets to Ethereum.
If you have not done yet, please create a project at Infura to connect
to the Ethereum Mainnet. You can find your Infura project ID under
your project's settings. For more help, look
here.


Managing and investing fund at the right place to grow is always being a challenging task. The fund collects the capital of the investors, and then its manager uses the capital to invest in the market, exchange, bonds and so on. However, the crypto market is uncontrolled, complex and full of uncertainty. Hence, making money in the financial market is a very difficult task that is worth study. Finaura's AI based services solve the exact same problem for you.
Choosing representative digital assets to offer cross-section can be a challenge. The Finaura provide cross-section services to make a difference to the way people make their investments with the most potential.
With the unrivaled rise of crypto, many new opportunities are arising in field of investment. Finaura provides highly scalable Machine Learning and AI service through sustainable potentialities for your fund.
Let System and Expert plan for your investment. Importantly, individual investors with little knowledge of crypto-currency content do not want to miss opportunities to be exposed to undervalued digital assets.
Finaura analytical services do in-depth market research for all available crypto-currency and create most profitable Model portfolios, asset allocation and algorithm-driven recommendations for you.
Copyright (c) 2018 Finaura Inc. All Rights Reserved. Powered by D FROZENSOFT PRIVATE LIMITED


Typeractive
Welcome
Random (R)
Categories (C)
Done!
Time Taken
Words Per Minute
Accuracy
Retry (R)
Menu (M)
Paused
Restart (R)
Resume (Esc)
Quit (Q)
Pick A Category
Back (Esc)
Play
Loading
0
WPM
0:00
100.0%
☰


Add your itinerary below using the "Add Train" form and then submit your results. Your results will be added to the page in real time!


idaal.com is a consortium of Intellectual Disability Libraries established to provide easy and comprehensive access to up-to-date information in this and related fields thereby supporting research, best practice and education in our services.


Veritas Cluster Server CP server install and configuration guide
When you read this article, i assume you already know the split-brain issue in Cluster. VCS have CP server to avoid the split-brain issue. also you can use SCSI3-PR func if your SAN storage support that.
We mainly focus on CP server setup and Configure the cluster to use CP servers.
=== Part 1, Setup CPS server ===
CP server setup. you can install SFHA all package. which include the CPS server
VRTScps All Cluster Server – Coordination Point Server
# Quick Steps:
/opt/VRTS/install/installvcs61 -configcps
# Manual Steps without VCS, because CPS can run alone.
# Once you installed, create CPS configuration.

root@salt/etc/VRTScps/db/current:$ cat /etc/vxcps.conf

cps_name=salt

vip=[10.x.x.x] # update x.x.x to your VIP

port=14250

security=0

db=/etc/VRTScps/db

# then start CPS

/opt/VRTScps/bin/vxcpserv

# check CPS
| netstat -anpt | grep 14250 |
tcp 0 0 <IP_ADDRESS>:14250 <IP_ADDRESS>:* LISTEN 26041/vxcpserv
tcp 0 0 10.x.x.x:14250 <IP_ADDRESS>:* LISTEN 26041/vxcpserv
=== Part 2, Setup Password less from Cluster node to CPS server ===
When client want to talk/reg the CPS server. they need ssh passwordless from client to CPS server. so this need to be setup before Part 3.
=== Part 3, Configure Cluster node to use CPS server ===
root@beihdp01a ~]# /opt/VRTS/install/installvcs -fencing
Veritas Cluster Server 5.1 SP1 Install Program
Copyright (c) 2010 Symantec Corporation. All rights reserved. Symantec, the Symantec Logo are trademarks or registered trademarks of Symantec Corporation or its affiliates
in the U.S. and other countries. Other names may be trademarks of their respective owners.
The Licensed Software and Documentation are deemed to be “commercial computer software” and “commercial computer software documentation” as defined in FAR Sections 12.212
and DFARS Section 227.7202.
Logs are being written to /var/tmp/installvcs-201312040324pwh while installvcs is in progress.
Checking communication on beihdp01a ……………………………………………………………………………………………………………….. Done
Checking release compatibility on beihdp01a ………………………………………………………………………………………………………… Done
Checking VCS installation on beihdp01a ………………………………………………………………………………………………………. <IP_ADDRESS>
Veritas Cluster Server 5.1 SP1 Configure Program
Cluster information verification:
Cluster Name: beihdp
Cluster ID Number: 10
Systems: beihdp01a beihdp01b beihdp01c
Would you like to configure I/O fencing on the cluster? [y,n,q] y
Checking communication on beihdp01a ……………………………………………………………………………………………………………….. Done
Checking release compatibility on beihdp01a ………………………………………………………………………………………………………… Done
Checking VCS installation on beihdp01a ………………………………………………………………………………………………………. <IP_ADDRESS>
Checking communication on beihdp01b ……………………………………………………………………………………………………………….. Done
Checking release compatibility on beihdp01b ………………………………………………………………………………………………………… Done
Checking VCS installation on beihdp01b ………………………………………………………………………………………………………. <IP_ADDRESS>
Checking communication on beihdp01c ……………………………………………………………………………………………………………….. Done
Checking release compatibility on beihdp01c ………………………………………………………………………………………………………… Done
Checking VCS installation on beihdp01c ………………………………………………………………………………………………………. <IP_ADDRESS>
Veritas Cluster Server 5.1 SP1 Configure Program
Fencing configuration
1) Configure CP client based fencing
2) Configure disk based fencing
3) Configure fencing in disabled mode
Select the fencing mechanism to be configured in this Application Cluster: [1-3,q] 1
Does your storage environment support SCSI3 PR? [y,n,q] (y) n
In virtualized environments that do not support SCSI-3 PR, VCS attempts to minimize the chances of data corruption with discreet use of timings in the event of unreachable
nodes or network partition. However, if a server becomes unresponsive, VCS assumes that the node has left the cluster and reconfigures itself.
This feature only works with UseFence Cluster attribute set to SCSI3 and all coordination points being CP servers
In this environment, either Non-SCSI3 fencing can be configured or fencing can be configured in disabled mode
Do you want to configure Non-SCSI3 fencing? [y,n,q] (y)
Enter the total number of co-ordination points. All co-ordination points should be CP servers: [b] (3) 1
Warning: Symantec recommends at least three or more odd number of coordination points to avoid a single point of failure. However, if fencing is configured to use a single
CP server, it is strongly recommended to make the CP server highly available by configuring it on a SFHA cluster. It is important to note that during a failover of the CP
server in the SFHA cluster, if there is a network partition on the client cluster at the same time, the whole client cluster will be brought down because arbitration
facility will not be available for the duration of the failover.
Press [Enter] to continue:
Veritas Cluster Server 5.1 SP1 Configure Program
You are now going to be asked for the Virtual IP addresses/hostnames of the CP Servers. Note that the installer assumes these values to be the identical as viewed from all
the client cluster nodes.
Press [Enter] to continue:
Enter the Virtual IP address/fully qualified host name for the Co-ordination Point Server #1: [b] 10.x.x.x
Enter the port in the range [49152, 65535] which the Co-ordination Point Server <IP_ADDRESS> would be listening on or simply accept the default port suggested: [b] (14250)
Veritas Cluster Server 5.1 SP1 Configure Program
CPS based fencing configuration: Coordination points verification
Total number of coordination points being used: 1
CP Server (Port):
- <IP_ADDRESS> (14250)
Is this information correct? [y,n,q] (y)
Veritas Cluster Server 5.1 SP1 Configure Program
While it is recommended to have secure communication configured between CP Servers and CP client cluster, the client cluster must be in the same mode (secure or non-secure)
as the CP servers are.
Since the CP servers are configured in non-secure mode, the installer will not try to configure the client cluster as a secure cluster.
Press [Enter] to continue:
Veritas Cluster Server 5.1 SP1 Configure Program
CPS based fencing configuration: Client cluster verification
CPS Admin utility : /opt/VRTScps/bin/cpsadm
Cluster ID: 10
Cluster Name: beihdp
UUID for the above cluster: {58f57018-1dd2-11b2-bf24-8d7f951ee738}
Is this information correct? [y,n,q] (y)
Veritas Cluster Server 5.1 SP1 Configure Program
Updating client cluster information on CP Server 10.x.x.x
Adding the client cluster to the CP Server 10.x.x.x ………………………………………………………………………………………………. Done
Registering client node beihdp01a with CP Server 10.x.x.x …………………………………………………………………………………………. Done
Adding CPClient user for communicating to CP Server 10.x.x.x ………………………………………………………………………………………. Done
Adding cluster beihdp to the CPClient user on CP Server 10.x.x.x …………………………………………………………………………………… Done
Registering client node beihdp01b with CP Server 10.x.x.x …………………………………………………………………………………………. Done
Adding CPClient user for communicating to CP Server 10.x.x.x ………………………………………………………………………………………. Done
Adding cluster beihdp to the CPClient user on CP Server 10.x.x.x …………………………………………………………………………………… Done
Registering client node beihdp01c with CP Server 10.x.x.x …………………………………………………………………………………………. Done
Adding CPClient user for communicating to CP Server 10.x.x.x ………………………………………………………………………………………. Done
Adding cluster beihdp to the CPClient user on CP Server 10.x.x.x …………………………………………………………………………………… Done
Do you want to configure CP Agent on the client cluster? [y,n,q] (y)
There is already at least one group with a resource of type ‘CoordPoint’ as displayed below. Manually check if it has all the attributes set correctly.
#Resource Attribute System Value
coordpoint Group global vxfen
Press [Enter] to continue:
Stopping VCS on beihdp01a ………………………………………………………………………………………………………………………… Done
Stopping VCS on beihdp01b ………………………………………………………………………………………………………………………… Done
Stopping VCS on beihdp01c ………………………………………………………………………………………………………………………… Done
Updating /etc/vxfenmode file on beihdp01a ………………………………………………………………………………………………………….. Done
Updating /etc/vxenviron file on beihdp01a ………………………………………………………………………………………………………….. Done
Updating /etc/sysconfig/vxfen file on beihdp01a …………………………………………………………………………………………………….. Done
Updating /etc/llttab file on beihdp01a …………………………………………………………………………………………………………….. Done
Updating /etc/vxfenmode file on beihdp01b ………………………………………………………………………………………………………….. Done
Updating /etc/vxenviron file on beihdp01b ………………………………………………………………………………………………………….. Done
Updating /etc/sysconfig/vxfen file on beihdp01b …………………………………………………………………………………………………….. Done
Updating /etc/llttab file on beihdp01b …………………………………………………………………………………………………………….. Done
Updating /etc/vxfenmode file on beihdp01c ………………………………………………………………………………………………………….. Done
Updating /etc/vxenviron file on beihdp01c ………………………………………………………………………………………………………….. Done
Updating /etc/sysconfig/vxfen file on beihdp01c …………………………………………………………………………………………………….. Done
Updating /etc/llttab file on beihdp01c …………………………………………………………………………………………………………….. Done
Starting Fencing on beihdp01a …………………………………………………………………………………………………………………….. Done
Starting Fencing on beihdp01b …………………………………………………………………………………………………………………….. Done
Starting Fencing on beihdp01c …………………………………………………………………………………………………………………….. Done
Updating main.cf with fencing …………………………………………………………………………………………………………………….. Done
Starting VCS on beihdp01a ………………………………………………………………………………………………………………………… Done
Starting VCS on beihdp01b ………………………………………………………………………………………………………………………… Done
Starting VCS on beihdp01c ………………………………………………………………………………………………………………………… Done
I/O Fencing configuration …………………………………………………………………………………………………………………………  Done
Wed Dec 4 03:06:56 GMT 2013 calling mod_unload.
Wed Dec 4 03:25:57 GMT 2013 Invoked vxfen. Starting
Wed Dec 4 03:25:57 GMT 2013 starting vxfen..
Wed Dec 4 03:26:50 GMT 2013 calling start_fun.
Wed Dec 4 03:26:50 GMT 2013 found vxfenmode file
Wed Dec 4 03:26:50 GMT 2013 calling /sbin/vxfen-startup in bg
Wed Dec 4 03:26:50 GMT 2013 starting vxfen.. Done
Wed Dec 4 03:26:51 GMT 2013 starting in vxfen-startup
Wed Dec 4 03:26:51 GMT 2013 case -m :: fencing mechanism cps
Wed Dec 4 03:26:51 GMT 2013 executing local_info.sh: begin
Wed Dec 4 03:26:53 GMT 2013 output was security=0
single_cp=1
Wed Dec 4 03:26:53 GMT 2013 executing local_info.sh: end
Wed Dec 4 03:26:53 GMT 2013 calling regular vxfenconfig
Wed Dec 4 03:27:17 GMT 2013 return value from above operation is 0
Wed Dec 4 03:27:17 GMT 2013 output was Log Buffer: 0xffffffff88e082c0
VXFEN vxfenconfig NOTICE Driver will use customized fencing – mechanism cps
Wed Dec 4 03:27:17 GMT 2013 done with script.
# Issue 1.
Wed Dec 4 02:24:57 GMT 2013 output was VXFEN vxfenconfig ERROR V-11-2-1043 Detected a preexisting split brain. Unable to join cluster.
Log Buffer: 0xffffffff88d292c0
# clean the sqlite db (/etc/VRTScps/db/current/cps_db) from CPS server or you can clean up the record for your new Cluster. then let the installvcs -fencing script moving forward.
# show cluster info from CP server
$cd /etc/VRTScps/db/current
$sqlite cps_db
sqlite> .tables
clusters nodes nodesspv user_cluster users
sqlite> select * from nodes;
0,{58f57018-1dd2-11b2-bf24-8d7f951ee738},1,beihdp01a
1,{58f57018-1dd2-11b2-bf24-8d7f951ee738},0,beihdp01b
2,{58f57018-1dd2-11b2-bf24-8d7f951ee738},1,beihdp01c
sqlite> select * from clusters;
{58f57018-1dd2-11b2-bf24-8d7f951ee738},beihdp
# Issue 2, Even the coordpoint online. the SG still doesn’t get online
Solution:
Add Phantom to vxfen SG.
vxfen beihdp01a ONLINE
————————————————————————-
vxfen beihdp01c ONLINE
coordpoint beihdp01a ONLINE
coordpoint beihdp01c ONLINE
phantom beihdp01a ONLINE
phantom beihdp01c ONLINE
# Refer
http://www.symantec.com/business/support/index?page=content&id=HOWTO41888


Loading chart...
SC Disabilities
Notes
Orders
Appointments
Medications
Postings
Allergies
Labs
Consults
Non-VA Meds
Vitals
Radiology
Discharges