Understanding Arrays in Go

Introduction

An array in Go is an ordered sequence of elements that has its capacity defined at creation time. Once an array has allocated its size, the size can no longer be changed. Because the size of an array is static, the data structure only needs to allocate memory once, as opposed to a variable length data structure that must dynamically allocate memory so that it can become larger or smaller in the future.

Although the fixed length of arrays can make them somewhat rigid to work with, the one-time memory allocation can increase the speed and performance of your program. Because of this, developers typically use arrays when optimizing programs. In Go, slices are the variable length version of arrays. Slices provide more flexibility and constitute what you would think of as arrays in other languages.

In this article, you will learn how to declare an array, how to call individual elements using indexing, how to slice the array into smaller sets, and the difference between an array and a slice in Go.

Defining an Array

Arrays are defined by declaring the size of the array in brackets [ ], followed by the data type of the elements. An array in Go must have all its elements be the same data type. After the data type, you can declare the individual values of the array elements in curly brackets { }.

The following is the general schema for declaring an array:

[capacity]data_type{element_values} 

Note: It is important to remember that every declaration of a new array creates a distinct type. So, although [2]int and [3]int both have integer elements, their differing capacities make their data types incompatible.

If you do not declare the values of the array’s elements, the default is zero-valued, which means that the array elements of the array will be empty. For integers, this is represented by 0, and for strings this is represented by an empty string.

For example, the following array numbers has three integer elements that do not yet have a value:

var numbers [3]int 

If you printed numbers, you would recieve the following output:

Output
[0 0 0]

If you would like to assign the values of the elements when you create the array, place the values in curly brackets. An array of strings with set values looks like this:

[4]string{"blue coral", "staghorn coral", "pillar coral", "elkhorn coral"} 

You can store an array in a variable and print it out:

coral := [4]string{"blue coral", "staghorn coral", "pillar coral", "elkhorn coral"} fmt.Println(coral) 

Running a program with the preceding lines would give you the following output:

Output
[blue coral staghorn coral pillar coral elkhorn coral]

Notice that there is no delineation between the elements in the array when it is printed, making it difficult to tell where one element ends and another begins. Because of this, it is sometimes helpful to use the fmt.Printf function instead, which can format strings before printing them to the screen. Provide the %q verb with this command to instruct the function to put quotation marks around the values:

fmt.Printf("%q\n", coral) 

This will result in the following:

Output
["blue coral" "staghorn coral" "pillar coral" "elkhorn coral"]

Now each item is quoted. The \n verb instructs to the formatter to add a line return at the end.

With a general idea of how to declare arrays and what they consist of, you can now move on to learning how to specify elements in an array with indexes.

Indexing Arrays

Each element in an array can be called individually through indexing. Each element corresponds to an index number, which is an int value starting from the index number 0 and counting up.

For the coral array from the earlier example, the index breakdown looks like this:

“blue coral” “staghorn coral” “pillar coral” “elkhorn coral”
0 1 2 3

The first element, the string 'blue coral', starts at index 0, and the list ends at index 3 with the item 'elkhorn coral'.

You can call a discrete element of the array by referring to its index number in brackets after the variable in which the array is stored:

fmt.Println(coral[2]) 

This will print the following:

Output
pillar coral

The index numbers for this array range from 03, so to call any of the elements individually and assign them a value, you could refer to the index numbers like this:

coral[0] = "blue coral" coral[1] = "staghorn coral" coral[2] = "pillar coral" coral[3] = "elkhorn coral" 

If you call the array coral with an index number greater than 3, it will be out of range, and Go will consider the action invalid:

fmt.Println(coral[22]) 
Output
invalid array index 22 (out of bounds for 4-element array)

When indexing an array, you must always use a positive number. Unlike some languages that let you index backwards with a negative number, doing that in Go will result in an error:

fmt.Println(coral[-1]) 
Output
invalid array index -1 (index must be non-negative)

Now that you know how to work with individual elements in an array, you can learn how to slice arrays to select a range of elements.

Slicing Arrays

By using index numbers to determine beginning and endpoints, you can call a subsection of the values within an array. This is called slicing the array. You can do this by creating a range of index numbers separated by a colon, in the form of [first_index:second_index].

Let’s say you would like to just print the middle items of coral, without the first and last element. You can do this by creating a slice starting at index 1 and ending just before index 3:

fmt.Println(coral[1:3]) 

Running a program with this line would yield the following:

Output
[staghorn coral pillar coral]

When creating a slice, as in [1:3], the first number is where the slice starts (inclusive), and the second number is the sum of the first number and the total number of elements you would like to retrieve:

array[starting_index : (starting_index + length_of_slice)] 

In this instance, you called the second element (or index 1) as the starting point, and called two elements in total. This is how the calculation would look:

array[1 : (1 + 2)] 

Which is how you arrived at this notation:

coral[1:3] 

If you want to set the beginning or end of the array as a starting or end point of the slice, you can omit one of the numbers in the array[first_index:second_index] syntax. For example, if you want to print the first three items of the array coral — which would be "blue coral", "staghorn coral", and "pillar coral" — you can do so by typing:

fmt.Println(coral[:3]) 

This will print:

Output
[blue coral staghorn coral pillar coral]

This printed the beginning of the array, stopping right before index 3.

To include all the items at the end of an array, you would reverse the syntax:

fmt.Println(coral[1:]) 

This would give the following:

Output
[staghorn coral pillar coral elkhorn coral]

This section discussed calling individual parts of an array by slicing out subsections. Next, you’ll learn a specific function that Go uses for arrays: len().

Array Functions

In Go, len() is a built-in function made to help you work with arrays. Like with strings, you can calculate the length of an array by using len() and passing in the array as a parameter.

For example, to find how many elements are in the coral array, you would use:

len(coral) 

If you print out the length for the array coral, you’ll receive the following output:

Output
4

This gives the length of the array 4 in the int data type, which is correct because the array coral has four items:

coral := [4]string{"blue coral", "staghorn coral", "pillar coral", "elkhorn coral"} 

If you create an array of integers with more elements, you could use the len() function on this as well:

numbers := [13]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12} fmt.Println(len(numbers)) 

This would result in the following output:

Output
13

Although these example arrays have relatively few items, the len() function is especially useful when determining how many elements are in very large arrays.

Now that you know how to use len() to output the length of arrays, you can learn how arrays differ from another common data structure: slices.

How Arrays Differ from Slices

As mentioned before, the primary way in which arrays are different from slices is that the size of an array cannot be modified. This means that while you can change the values of elements in an array, you can’t make the array larger or smaller after it has been defined. A slice, on the other hand, can alter its length.

Let’s consider your coral array:

coral := [4]string{"blue coral", "staghorn coral", "pillar coral", "elkhorn coral"} 

Say you want to add the item "black coral" to this array. If you try to use the append() function with the array by typing:

coral = append(coral, "black coral") 

You will receive an error as your output:

Output
first argument to append must be slice; have [4]string

If you create an array and decide that you need it to have a variable length, you can convert it to a slice. To convert an array to a slice, use the slicing process you learned in the Slicing Arrays step of this tutorial, except this time select the entire slice by omitting both of the index numbers that would determine the endpoints:

coral[:] 

Keep in mind that you can’t convert the variable coral to a slice itself, since once a variable is defined in Go, its type can’t be changed. To work around this, you can copy the entire contents of the array into a new variable as a slice:

coralSlice := coral[:] 

If you printed coralSlice, you would receive the following output:

Output
[blue coral staghorn coral pillar coral elkhorn coral]

Now, try to use append() with the newly converted slice:

newSlice := append(coralSlice, "black coral") fmt.Printf("%q\n", newSlice) 

This will output the slice with the added element:

Output
["blue coral" "staghorn coral" "pillar coral" "elkhorn coral" "black coral"]

Conclusion

In this tutorial, you learned that the array data type is a sequenced data type with a fixed length, which makes it faster for Go to process at the cost of flexibility. Arrays also can help with communication on a team of developers: When others collaborate with you on your code, your use of arrays will convey to them that you don’t intend for their lengths to be changed.

With this data type in your tool box, you can now go more in-depth learning the variable length version of this structure: slices.

DigitalOcean Community Tutorials

Understanding Tableau Prep and Conductor: Building a Viz with Flow Data

Understanding Tableau Prep and Conductor: Building a Viz with Flow Data

In the last four blog posts in this series, we created an 18-step workflow that provides a hyper extract file. I’m going to test my set by building a view in Tableau Desktop. While I could just publish the flow and use an output file as my starting point, I’m going to use the last cleaning step in the flow to launch Tableau.

Of course, the whole point in creating the workflow using the Superstore data with the Census data was to normalize sales by State for the population in each state. Now that we’ve confirmed the dataset is complete and contains the data we need to build views, we want to Create:

building a visualization with flow data in Tableau

In the next post in this series, I’ll show you how to publish your workflow to Tableau Server. We’ll also discuss how you can use the Tableau Data Management add-on to Tableau Server to automate workflow runs to refresh data sources that you are curating to your Tableau Server users.

The post Understanding Tableau Prep and Conductor: Building a Viz with Flow Data appeared first on InterWorks.

InterWorks

Understanding Tableau Prep and Conductor: Facilitating a Join with Aggregation

Understanding Tableau Prep and Conductor: Facilitating a Join with Aggregation

In the previous three posts in this series, we used Tableau Prep Builder to create a workflow to join six tables from two data sources. Our flow contains 11 steps. The challenge presented with the data we have from the Census comes from the different levels of detail (LOD) our sales data has—specific transactions every day for the last four years—and the Census data, which includes population data aggregated at the State-level for the same four years. The Census data is much less detailed.

This is a common issue with financial data, for example, because budget data tends to be less detailed than the transaction-level details you can obtain from business systems. So, we need to use an aggregate step to reduce the LOD of the Superstore sales data so that it’s the same as the Census data.

Using the Aggregate Step in Tableau Prep

The Census data provides population data by State and Year. We’ll use an aggregate step to reduce the detail in the Superstore data to match the Census data.

After performing the aggregation of the Superstore data, we can now get a resulting set that combines sales and population data for every state. The Census data actually includes information for Alaska and Hawaii, for which we don’t have any sales. That’s fine. Delaware is also mismatched in 2018 because there were no sales in the Superstore data that year. By using the aggregate step, we’ve now brought both data sources together and achieved a consistent LOD.

Creating a Per-Capital Sales Calculation

The primary reason I wanted to bring in the Census data was to normalize the sales by state for population. Superstore is anonymized retail sales information. While it’s useful to know that California has the most sales in this data, how does Vermont compare to California when you take into account the population differences between states?

Saving Your Tableau Prep Workflow

At the end of the last video, I showed you how to add an output step, save a workflow and then run the workflow to generate a Hyper output file that we’ll use to build a visualization of the data. Saving the workflow enables you to reuse it later. Running the workflow generates the Hyper data.

Cleaning up the Workflow Visualization

We now have a workflow that consists of 18 steps. Let’s step back for a moment and enhance the information in our workflow so that other people can more easily follow its logic:

The video shows how you can change step colors and add comments, making each step easier for others to follow and understand. I didn’t rename any of them. You may also experiment with the ways you can use color, descriptions and step renaming to make your flows easier for other people to track with.

In the next post in this series, I’m going to build a visualization using the dataset we created in the workflow.

The post Understanding Tableau Prep and Conductor: Facilitating a Join with Aggregation appeared first on InterWorks.

InterWorks

Understanding Tableau Prep and Conductor: Clean and Join Steps

Understanding Tableau Prep and Conductor: Clean and Join Steps

The last post in this series showed you how to use the Wildcard union and the Manual union to join four years of sales data that was stored in four different worksheets. In this post, you’ll see how the cleaning step can be used to do the following:

  • Change field-data roles
  • Group and replace members of a specific field set
  • Change the data types of a field and rename fields

All this can be done by using the Profile Cards within the Profile Pane in Tableau Prep Builder.

Using the Clean Step in Tableau Prep

The cleaning step behaves a lot like the data interpreter in Tableau Desktop, but it adds additional visualizations in the Profile Pane and the field Profile Cards that help you understand the shape and contents of each field. In addition, clicking on elements within the Profile Cards highlights related details in the other field cards. I find myself using the cleaning step frequently just to examine the results of prior steps.

Adding a Join Step

The Superstore dataset also includes another worksheet containing the names of Regional Managers. Regional Managers are assigned groups of States. We’ll use a join to add that information to the flow:

Now that the sales data from the Superstore tables have been cleaned up, we will bring some public data from the Census Bureau so that we can enhance our sales data by normalizing sales for the population by state.

Adding the Census Data into the Flow

I’ve been using Census data for many years. It’s useful when you want to account for the population density in analyses. In the example we’re building, this data will ultimately be used to express the sales by state in a way that accounts for the population density of each geography.

Using the Pivot Step and Tableau Prep Builder

The Census data isn’t perfectly formatted. We’ll use Prep Builder to fix the structural problems in that dataset:

In the video, I chose to do most of the field clean-up in the pivot step. I could have performed the same cleaning operations in the cleaning step that I added after the pivot. If the work you’re doing is going to be utilized only by use, fewer steps may save you time. If you work with a team of people who are new to Prep Builder, adding more steps to segregate individual cleaning operations may make your flow easier for others to understand. There aren’t hard and fast rules.

This workflow now includes two different data sources and six tables. You’ve seen two different ways to create a union; you’ve seen a join step and a pivot step; and you’ve learned about different ways you can use the cleaning step to improve the formatting and consistency of the data in the workflow. My colleague Katie wrote a blog post that takes a closer look at splitting and pivoting your data, so read it if you need more in-depth insights into those steps. For further information on cleansing your data, look at my colleague Spencer‘s blog on the topic.

In the next post in this series, we’re going to join the Superstore data to the Census data. Because these two data sources are not aggregated in the same way, we’ll be presented with a challenge that we’ll address with an aggregate step.

The post Understanding Tableau Prep and Conductor: Clean and Join Steps appeared first on InterWorks.

InterWorks

Understanding Boolean Logic in Go

The Boolean data type (bool) can be one of two values, either true or false. Booleans are used in programming to make comparisons and to control the flow of the program.

Booleans represent the truth values that are associated with the logic branch of mathematics, which informs algorithms in computer science. Named for the mathematician George Boole, the word Boolean always begins with a capitalized B.

The data type in Go for Boolean is bool, all lowercase. The values true and false will always be with a lowercase t and f respectively, as they are special values in Go.

This tutorial will cover the basics you’ll need to understand how the bool data type works, including Boolean comparison, logical operators, and truth tables.

Comparison Operators

In programming, comparison operators are used to compare values and evaluate down to a single Boolean value of either true or false.

The table below shows Boolean comparison operators.

Operator What it means
== Equal to
!= Not equal to
< Less than
> Greater than
<= Less than or equal to
>= Greater than or equal to

To understand how these operators work, let’s assign two integers to two variables in a Go program:

x := 5 y := 8 

In this example, since x has the value of 5, it is less than y which has the value of 8.

Using those two variables and their associated values, let’s go through the operators from the preceding table. In this program, you’ll ask Go to print out whether each comparison operator evaluates to either true or false. To help better understand this output, you’ll have Go also print a string to show you what it’s evaluating:

package main  import "fmt"  func main() {     x := 5     y := 8      fmt.Println("x == y:", x == y)     fmt.Println("x != y:", x != y)     fmt.Println("x < y:", x < y)     fmt.Println("x > y:", x > y)     fmt.Println("x <= y:", x <= y)     fmt.Println("x >= y:", x >= y) } 
Output
x == y: false x != y: true x < y: true x > y: false x <= y: true x >= y: false

Following mathematical logic, Go has evaluated the following from the expressions:

  • Is 5 (x) equal to 8 (y)? false
  • Is 5 not equal to 8? true
  • Is 5 less than 8? true
  • Is 5 greater than 8? false
  • Is 5 less than or equal to 8? true
  • Is 5 not less than or equal to 8? false

Although integers were used here, you could substitute them with float values.

Strings can also be used with Boolean operators. They are case-sensitive unless you use an additional string method.

You can look at how strings are compared in practice:

Sammy := "Sammy" sammy := "sammy"  fmt.Println("Sammy == sammy: ", Sammy == sammy) 
Output
Sammy == sammy: false

The string Sammy is not equal to the string sammy, because they are not exactly the same; one starts with an uppercase S and the other with a lowercase s. But, if you add another variable that is assigned the value of Sammy, then they will evaluate to equal:

Sammy := "Sammy" sammy := "sammy" alsoSammy := "Sammy"  fmt.Println("Sammy == sammy: ", Sammy == sammy) fmt.Println("Sammy == alsoSammy", Sammy == alsoSammy) 
Output
Sammy == sammy: false Sammy == alsoSammy true

You can also use the other comparison operators including > and < to compare two strings. Go will compare these strings lexicographically using the ASCII values of the characters.

You can also evaluate Boolean values with comparison operators:

t := true f := false  fmt.Println("t != f: ", t != f) 
Output
t != f: true

The preceding code block evaluated that true is not equal to false.

Note the difference between the two operators = and ==.

x = y   // Sets x equal to y x == y  // Evaluates whether x is equal to y 

The first = is the assignment operator, which will set one value equal to another. The second, ==, is a comparison operator and will evaluate whether two values are equal.

Logical Operators

There are two logical operators that are used to compare values. They evaluate expressions down to Boolean values, returning either true or false. These operators are &&, ||, and !, and are defined in the list below:

  • && (x && y) is the and operator. It is true if both statements are true.
  • || (x || y) is the or operator. It is true if at least one statement is true.
  • ! (!x) is the not operator. It is true only if the statement is false.

Logical operators are typically used to evaluate whether two or more expressions are true or not true. For example, they can be used to determine if the grade is passing and that the student is registered in the course, and if both cases are true, then the student will be assigned a grade in the system. Another example would be to determine whether a user is a valid active customer of an online shop based on whether they have store credit or have made a purchase in the past 6 months.

To understand how logical operators work, let’s evaluate three expressions:

fmt.Println((9 > 7) && (2 < 4))   // Both original expressions are true fmt.Println((8 == 8) || (6 != 6)) // One original expression is true fmt.Println(!(3 <= 1))            // The original expression is false 
Output
true true true

In the first case, fmt.Println((9 > 7) && (2 < 4)), both 9 > 7 and 2 < 4 needed to evaluate to true since the and operator was used.

In the second case, fmt.Println((8 == 8) || (6 != 6)), since 8 == 8 evaluated to true, it did not make a difference that 6 != 6 evaluates to false because the or operator was used. If you had used the and operator, this would evaluate to false.

In the third case, fmt.Println(!(3 <= 1)), the not operator negates the false value that 3 <=1 returns.

Let’s substitute floats for integers and aim for false evaluations:

fmt.Println((-0.2 > 1.4) && (0.8 < 3.1))  // One original expression is false fmt.Println((7.5 == 8.9) || (9.2 != 9.2)) // Both original expressions are false fmt.Println(!(-5.7 <= 0.3))               // The original expression is true 

In this example:

  • and must have at least one false expression evaluate to false.
  • or must have both expressions evaluate to false.
  • ! must have its inner expression be true for the new expression to evaluate to false.

If these results seem unclear to you, go through some truth tables for further clarification.

You can also write compound statements using &&, ||, and !:

!((-0.2 > 1.4) && ((0.8 < 3.1) || (0.1 == 0.1))) 

Take a look at the inner-most expression first: (0.8 < 3.1) || (0.1 == 0.1). This expression evaluates to true because both mathematical statements are true.

Next, Go takes the returned value true and combines it with the next inner expression: (-0.2 > 1.4) && (true). This example returns false because the mathematical statement -0.2 > 1.4 is false, and (false) and (true) returns false.

Finally, we have the outer expression: !(false), which evaluates to true, so the final returned value if we print this statement out is:

Output
true

The logical operators &&, ||, and ! evaluate expressions and return Boolean values.

Truth Tables

There is a lot to learn about the logic branch of mathematics, but you can selectively learn some of it to improve your algorithmic thinking when programming.

The following are truth tables for the comparison operator ==, and each of the logic operators &&, || and !. While you may be able to reason them out, it can also be helpful to memorize them as that can make your programming decision-making process quicker.

== (equal) Truth Table

x == y Returns
true == true true
true == false false
false == true false
false == false true

&& (and) Truth Table

x and y Returns
true and true true
true and false false
false and true false
false and false false

|| (or) Truth Table

x or y Returns
true or true true
true or false true
false or true true
false or false false

! (not) Truth Table

not x Returns
not true false
not false true

Truth tables are common mathematical tables used in logic, and are useful to keep in mind when constructing algorithms (instructions) in computer programming.

Using Boolean Operators for Flow Control

To control the stream and outcomes of a program in the form of flow control statements, you can use a condition followed by a clause.

A condition evaluates down to a Boolean value of true or false, presenting a point where a decision is made in the program. That is, a condition would tell you if something evaluates to true or false.

The clause is the block of code that follows the condition and dictates the outcome of the program. That is, it is the “do this” part of the construction “If x is true, then do this.”

The code block below shows an example of comparison operators working in tandem with conditional statements to control the flow of a Go program:

if grade >= 65 {                 // Condition     fmt.Println("Passing grade") // Clause } else {     fmt.Println("Failing grade") } 

This program will evaluate whether each student’s grade is passing or failing. In the case of a student with a grade of 83, the first statement will evaluate to true, and the print statement of Passing grade will be triggered. In the case of a student with a grade of 59, the first statement will evaluate to false, so the program will move on to execute the print statement tied to the else expression: Failing grade.

Boolean operators present conditions that can be used to decide the eventual outcome of a program through flow control statements.

Conclusion

This tutorial went through comparison and logical operators belonging to the Boolean type, as well as truth tables and using Booleans for program flow control.

DigitalOcean Community Tutorials