问:
What is an LR(2) parser? How does it differ from an LR(1) parser?
I'm familiar with LR(1) parsers, which are usually taught in traditional compilers courses. I know that LR(2) parsers exist, but I've never seen one constructed before.

How is an LR(2) parser constructed? How does it differ from an LR(1) parser?

答:
In many ways, an LR(2) parser works similarly to an LR(1) parser. It traces out a rightmost derivation in reverse, maintains a stack, executes shift and reduce actions on a stack, has states that consist of sets of LR items, etc. There are, however, a few major differences:

An LR(2) parser maintains two tokens of lookahead for each LR item, rather than just a single token of lookahead as in LR(1).

The rules for how a shift works differs from the standard rules of an LR(1) parser and requires an additional notion of lookahead called dot lookahead not present in LR(1) parsers.

The width of the action table for an LR(2) parser is much larger than that of an LR(1) parser, though, counterintuitively, the goto table is the same width.

To motivate how this works, let's take an example of an LR(2) grammar. (This grammar is derived from one mentioned in @rici's excellent answer to this earlier question).

S → RS | R

R → abT

T → aT | c | ε

To build our LR(2) parser for this grammar, we'll begin, as usual, by augmenting the grammar with a production of the form S' → S:

S' → S

S → RS | R

R → abT

T → aT | c | ε

Now, we start generating configurating sets. We begin, as with an LR(1) parser, with the production S' → S. This is shown here:

```<code>(1)
    S' -> .S  [$$]
</code>```

Notice here that the lookahead is $$, indicating two copies of the "end-of-stream" marker. In a traditional LR(1) (or SLR(1), or LALR(1)) parser, we'd have a lookahead here of $, just one copy of the end-of-stream marker, because in those parsers the token stream is suffixed with a single $ marker. But now that we’re in LR(2) Land, we have two tokens of lookahead, so our token stream will be sufficed with two end-of-stream markers.

We now start expanding out the other items in this configurating set. Since we have productions S → RS and S → R, we add these items:

```<code>(1)
    S' -> .S  [$$]
    S  -> .R  [$$]  // New
    S  -> .RS [$$]  // New
</code>```

Now, let's start chasing down what happens next. As in an LR(1) parser, since there are dots before the nonterminal R's here, we need to expand them out. As in LR(1) parsing, as we do so, we'll need to determine what lookaheads to use. We'll begin by expanding out the S -> .R [$$] item, like this:

```<code>(1)
    S' -> .S   [$$]
    S  -> .R   [$$]
    S  -> .RS  [$$]
    R  -> .abT [$$]  // New
</code>```

Next, let's expand out the S -> .RS [$$] option. This is an interesting case. We need to determine what the lookahead will be for the R productions discovered here. In an LR(1) parser, this is found by looking at the FIRST set of the remainder of the production. In an LR(2) parser, because we have two tokens of lookahead, we have to look a the FIRST2 set, which is the generalization of FIRST sets that lists the strings of length two that can appear at the front of the production, rather than the strings of length one that can appear there. In our case, FIRST2(S) = {ab} (do you see why?), so we have the following:

```<code>(1)
    S' -> .S   [$$]
    S  -> .R   [$$]
    S  -> .RS  [$$]
    R  -> .abT [$$]
    R  -> .abT [ab]  // New
</code>```

At this point, we've finished expanding out the first configurating set. It's now time to think about what we would do if we saw different characters next. Fortunately, in this case that's fairly easy, since the first character of any string produced by this grammar has to be an a. So let's see what happens if we encounter an a:

```<code>(2)
    R  -> a.bT [$$]
    R  -> a.bT [ab]
</code>```

Seems fine so far. Now what happens if we see a b here? That would take us to this spot:

```<code>(3)
    R  -> ab.T [$$]
    R  -> ab.T [ab]
</code>```

There are two LR(2) items here that have dots before a nonterminal, so we need to expand these out. Let's begin by expanding these for R -> ab.T [$$], giving the following:

```<code>(3)
    R  -> ab.T [$$]
    R  -> ab.T [ab]
    T  -> .aT  [$$]  // New
    T  -> .c   [$$]  // New
    T  -> .    [$$]  // New
</code>```

Next, we'll expand out the production for R -> ab.T [ab]:

```<code>(3)
    R  -> ab.T [$$]
    R  -> ab.T [ab]
    T  -> .aT  [$$]
    T  -> .c   [$$]
    T  -> .    [$$]
    T  -> .aT  [ab] // New
    T  -> .c   [ab] // New
    T  -> .    [ab] // New
</code>```

That fills out this configurating set. This is the first time we've found some reduce items that are complete (here, T -> . with the two different lookaheads). We also have some shift items here. So we have to ask - do we have a shift/reduce conflict or a reduce/reduce conflict here?

Let's begin with reduce/reduce conflicts. As is the case in LR(1) parsing, we have a reduce/reduce conflict when there are two different reduce items (items with the dot at the end) with the same lookaheads. Here, we have two different reduce items, but they have different lookaheads. That means we're fine on the reduce/reduce front.

Now, the interesting case. Do we have any shift/reduce conflicts here? This is where things change a bit from LR(1) parsing. As is the case in LR(1) parsing, we look at all the shift items in our set (items with a dot before a terminal) and all the reduce items in our set (items with the dot at the end). We're looking to see if there's any conflicts:

```<code>    T  -> .aT  [$$] // Shift
    T  -> .c   [$$] // Shift
    T  -> .    [$$] // Reduce
    T  -> .aT  [ab] // Shift
    T  -> .c   [ab] // Shift
    T  -> .    [ab] // Reduce
</code>```

The question, though, is what a shift/reduce conflict looks like here. In an LR(2) parser, we have two tokens of lookahead on which we base our decision of whether to shift or reduce. In the case of the reduce items, it's easy to see what two tokens of lookahead will lead us to reduce - it's the two-character lookahead in the brackets. On the other hand, consider the shift item T -> .c [ab]. What is the two-character lookahead here in which we'd shift? In the case of an LR(1) parser, we'd just say "oh, the dot's before the c, so we shift on c," but that's not sufficient here. Instead, we'd say that the lookahead associated with this shift item is ca, with the c coming from the production itself and the a coming from the first character of the item's lookahead.

Similarly, consider the shift item T -> .aT [$$]. We need two characters of lookahead, and we can see one of them pretty easily (the a after the dot). To get the second, we have to look at what T is capable of producing. There are three productions for T: one that replaces T with ε, one that replaces T with aT, and one that replaces T with c. This means that that any string that can be derived from T starts either with a or with c, or is the empty string. As a result, the item T -> .aT [$$] tells us to shift when seeing either ac or aa (what we'd get from the a and the c), or on a$ (what we'd get if we used the production T → ε, then picked up one of the $ characters from the normal lookahead.

More generally, following this same general procedure - using the terminal(s) after the dot, the terminals in the lookahead set for the item, and the characters that can appear at the front of any strings derivable from future nonterminals - we can compute the two-character lookaheads that we use to determine when to shift. In particular, we're left with this:

```<code>(3)
    R  -> ab.T [$$]
    R  -> ab.T [ab]
    T  -> .aT  [$$] // Shift  on aa, ac, a$
    T  -> .c   [$$] // Shift  on c$
    T  -> .    [$$] // Reduce on $$
    T  -> .aT  [ab] // Shift  on aa, ac
    T  -> .c   [ab] // Shift  on ca
    T  -> .    [ab] // Reduce on ab
</code>```

Fortunately, there are no shift/reduce conflicts here, because each two-character lookahead tells us to do something different.

Looking past the dot to determine when to shift is something new to LR(2) parsing that appears in LR(k > 1) parsing but not LR(1) parsing. In LR(1) parsing, we just need to look at the terminal past the dot. In LR(2) parsing, since we need more characters to determine what to do, we have to compute a secondary dot lookahead for each shift item. Specifically, the dot lookahead is determined as follows:

In a production A → α.tω [γ], where t is a terminal, the dot lookahead is the set of all strings of length 2 that can appear at the start of a string derivable from tωγ. Stated differently, a production A → α.tω [γ] has dot lookahead equal to FIRST2(tωγ).

With all of this in mind, we can build the full LR(2) parser and describe the actions associated with each state. The overall LR(2) parser looks like this:

```<code>(1)
    S' -> .S  [$$]
    S  -> .R  [$$]  // New
    S  -> .RS [$$]  // New
</code>```0

So now we have our LR(2) parser for this grammar. All that's left to do now is to encode this as an action and goto table, along the lines of what we do for an LR(1) parser.

As you might expect, the action table for an LR(2) parser differs from that of the action table for an LR(1) parser in that it's keyed by lookaheads given by two characters rather than just one character. This means that the action table will be much larger for an LR(2) parser than an LR(1) parser. Here's what that looks like here:

```<code>(1)
    S' -> .S  [$$]
    S  -> .R  [$$]  // New
    S  -> .RS [$$]  // New
</code>```1

As you can see, each entry here just says whether to shift or reduce. In practice, each reduce item would be tagged with which production you'd actually do the reduction for, but, um, I was too lazy to type that out.

In an LR(1) parsing table, you'd typically combine this table with the "goto" table saying where to go after seeing each symbol. That's due to a fortuitous coincidence. In an LR(1) parser, the size of the lookahead is 1, which happens to align with the fact that the goto table says where you're supposed to transition to after seeing the next character. In an LR(2) parser, the decision about whether to shift or reduce depends on two characters of lookahead, but the choice of where to go next after reading one more character of the input only depends on a single character. That is, even though you have two tokens of lookahead to decide whether to do, you only shift one character over at a time. This means that the goto table for an LR(2) parser looks a lot like the goto table for an LR(0) or LR(1) parser, and is shown here:

```<code>(1)
    S' -> .S  [$$]
    S  -> .R  [$$]  // New
    S  -> .RS [$$]  // New
</code>```2

So, to summarize:

The LR(2) parser uses two tokens of lookahead for each LR item. This means that we need to work with FIRST2 sets rather than FIRST sets, and introduces some new complexity when determining whether to shift or to reduce.

LR(2) parses have dot lookahead. For each shift item, we use the FIRST2 set to determine what characters can legally follow the dot from where we are, and shift on any of them.

The LR(2) action table is keyed by pairs of characters rather than single characters, but the goto table still is keyed by character.

Interestingly, once you know how to build an LR(2) parser, you can generalize the idea to build an LR(k) parser for any k ≥ 2. In particular, all the "new surprises" that arose here are the same ones that you'll see for larger and larger values of k.

In practice, LR(2) parsers are rarely used due to the size of their action tables and the fact that they generally have way more states than an LR(1) parser due to the increased lookaheads. But it's still worthwhile, IMHO, to see how to they work. It gives you a sense of how LR parsing works more generally.

Hope this helps!

A huge thanks to @AProgrammer's answer on cs.stackexchange.com about dot lookaheads versus item lookaheads, which helped me get a better sense of how dot lookaheads function and what their purpose is!

If you'd like to read the original paper on LR(k) parsing, which specs out the full rules for LR(k) parsing in full detail, check out "On the Translation of Languages from Left to Right" by Don Knuth.

Body:
In many ways, an LR(2) parser works similarly to an LR(1) parser. It traces out a rightmost derivation in reverse, maintains a stack, executes shift and reduce actions on a stack, has states that consist of sets of LR items, etc. There are, however, a few major differences:

An LR(2) parser maintains two tokens of lookahead for each LR item, rather than just a single token of lookahead as in LR(1).

The rules for how a shift works differs from the standard rules of an LR(1) parser and requires an additional notion of lookahead called dot lookahead not present in LR(1) parsers.

The width of the action table for an LR(2) parser is much larger than that of an LR(1) parser, though, counterintuitively, the goto table is the same width.

To motivate how this works, let's take an example of an LR(2) grammar. (This grammar is derived from one mentioned in @rici's excellent answer to this earlier question).

S → RS | R

R → abT

T → aT | c | ε

To build our LR(2) parser for this grammar, we'll begin, as usual, by augmenting the grammar with a production of the form S' → S:

S' → S

S → RS | R

R → abT

T → aT | c | ε

Now, we start generating configurating sets. We begin, as with an LR(1) parser, with the production S' → S. This is shown here:

(1)
    S' -> .S  [$$]

Notice here that the lookahead is $$, indicating two copies of the "end-of-stream" marker. In a traditional LR(1) (or SLR(1), or LALR(1)) parser, we'd have a lookahead here of $, just one copy of the end-of-stream marker, because in those parsers the token stream is suffixed with a single $ marker. But now that we’re in LR(2) Land, we have two tokens of lookahead, so our token stream will be sufficed with two end-of-stream markers.

We now start expanding out the other items in this configurating set. Since we have productions S → RS and S → R, we add these items:

(1)
    S' -> .S  [$$]
    S  -> .R  [$$]  // New
    S  -> .RS [$$]  // New

Now, let's start chasing down what happens next. As in an LR(1) parser, since there are dots before the nonterminal R's here, we need to expand them out. As in LR(1) parsing, as we do so, we'll need to determine what lookaheads to use. We'll begin by expanding out the S -> .R [$$] item, like this:

(1)
    S' -> .S   [$$]
    S  -> .R   [$$]
    S  -> .RS  [$$]
    R  -> .abT [$$]  // New

Next, let's expand out the S -> .RS [$$] option. This is an interesting case. We need to determine what the lookahead will be for the R productions discovered here. In an LR(1) parser, this is found by looking at the FIRST set of the remainder of the production. In an LR(2) parser, because we have two tokens of lookahead, we have to look a the FIRST2 set, which is the generalization of FIRST sets that lists the strings of length two that can appear at the front of the production, rather than the strings of length one that can appear there. In our case, FIRST2(S) = {ab} (do you see why?), so we have the following:

(1)
    S' -> .S   [$$]
    S  -> .R   [$$]
    S  -> .RS  [$$]
    R  -> .abT [$$]
    R  -> .abT [ab]  // New

At this point, we've finished expanding out the first configurating set. It's now time to think about what we would do if we saw different characters next. Fortunately, in this case that's fairly easy, since the first character of any string produced by this grammar has to be an a. So let's see what happens if we encounter an a:

(2)
    R  -> a.bT [$$]
    R  -> a.bT [ab]

Seems fine so far. Now what happens if we see a b here? That would take us to this spot:

(3)
    R  -> ab.T [$$]
    R  -> ab.T [ab]

There are two LR(2) items here that have dots before a nonterminal, so we need to expand these out. Let's begin by expanding these for R -> ab.T [$$], giving the following:

(3)
    R  -> ab.T [$$]
    R  -> ab.T [ab]
    T  -> .aT  [$$]  // New
    T  -> .c   [$$]  // New
    T  -> .    [$$]  // New

Next, we'll expand out the production for R -> ab.T [ab]:

(3)
    R  -> ab.T [$$]
    R  -> ab.T [ab]
    T  -> .aT  [$$]
    T  -> .c   [$$]
    T  -> .    [$$]
    T  -> .aT  [ab] // New
    T  -> .c   [ab] // New
    T  -> .    [ab] // New

That fills out this configurating set. This is the first time we've found some reduce items that are complete (here, T -> . with the two different lookaheads). We also have some shift items here. So we have to ask - do we have a shift/reduce conflict or a reduce/reduce conflict here?

Let's begin with reduce/reduce conflicts. As is the case in LR(1) parsing, we have a reduce/reduce conflict when there are two different reduce items (items with the dot at the end) with the same lookaheads. Here, we have two different reduce items, but they have different lookaheads. That means we're fine on the reduce/reduce front.

Now, the interesting case. Do we have any shift/reduce conflicts here? This is where things change a bit from LR(1) parsing. As is the case in LR(1) parsing, we look at all the shift items in our set (items with a dot before a terminal) and all the reduce items in our set (items with the dot at the end). We're looking to see if there's any conflicts:

    T  -> .aT  [$$] // Shift
    T  -> .c   [$$] // Shift
    T  -> .    [$$] // Reduce
    T  -> .aT  [ab] // Shift
    T  -> .c   [ab] // Shift
    T  -> .    [ab] // Reduce

The question, though, is what a shift/reduce conflict looks like here. In an LR(2) parser, we have two tokens of lookahead on which we base our decision of whether to shift or reduce. In the case of the reduce items, it's easy to see what two tokens of lookahead will lead us to reduce - it's the two-character lookahead in the brackets. On the other hand, consider the shift item T -> .c [ab]. What is the two-character lookahead here in which we'd shift? In the case of an LR(1) parser, we'd just say "oh, the dot's before the c, so we shift on c," but that's not sufficient here. Instead, we'd say that the lookahead associated with this shift item is ca, with the c coming from the production itself and the a coming from the first character of the item's lookahead.

Similarly, consider the shift item T -> .aT [$$]. We need two characters of lookahead, and we can see one of them pretty easily (the a after the dot). To get the second, we have to look at what T is capable of producing. There are three productions for T: one that replaces T with ε, one that replaces T with aT, and one that replaces T with c. This means that that any string that can be derived from T starts either with a or with c, or is the empty string. As a result, the item T -> .aT [$$] tells us to shift when seeing either ac or aa (what we'd get from the a and the c), or on a$ (what we'd get if we used the production T → ε, then picked up one of the $ characters from the normal lookahead.

More generally, following this same general procedure - using the terminal(s) after the dot, the terminals in the lookahead set for the item, and the characters that can appear at the front of any strings derivable from future nonterminals - we can compute the two-character lookaheads that we use to determine when to shift. In particular, we're left with this:

(3)
    R  -> ab.T [$$]
    R  -> ab.T [ab]
    T  -> .aT  [$$] // Shift  on aa, ac, a$
    T  -> .c   [$$] // Shift  on c$
    T  -> .    [$$] // Reduce on $$
    T  -> .aT  [ab] // Shift  on aa, ac
    T  -> .c   [ab] // Shift  on ca
    T  -> .    [ab] // Reduce on ab

Fortunately, there are no shift/reduce conflicts here, because each two-character lookahead tells us to do something different.

Looking past the dot to determine when to shift is something new to LR(2) parsing that appears in LR(k > 1) parsing but not LR(1) parsing. In LR(1) parsing, we just need to look at the terminal past the dot. In LR(2) parsing, since we need more characters to determine what to do, we have to compute a secondary dot lookahead for each shift item. Specifically, the dot lookahead is determined as follows:

In a production A → α.tω [γ], where t is a terminal, the dot lookahead is the set of all strings of length 2 that can appear at the start of a string derivable from tωγ. Stated differently, a production A → α.tω [γ] has dot lookahead equal to FIRST2(tωγ).

With all of this in mind, we can build the full LR(2) parser and describe the actions associated with each state. The overall LR(2) parser looks like this:

(1)
    S' -> .S   [$$]  // Go to 10
    S  -> .R   [$$]  // Go to 8
    S  -> .RS  [$$]  // Go to 8
    R  -> .abT [$$]  // Shift  on ab, go to (2)
    R  -> .abT [ab]  // Shift  on ab, go to (2)

(2)
    R  -> a.bT [$$]  // Shift  on ba, bc, b$, go to (3)
    R  -> a.bT [ab]  // Shift  on ba, bc,     go to (3)

(3)
    R  -> ab.T [$$] // Go to 7
    R  -> ab.T [ab] // Go to 7
    T  -> .aT  [$$] // Shift  on aa, ac, a$, go to (4)
    T  -> .c   [$$] // Shift  on c$,         go to (5)
    T  -> .    [$$] // Reduce on $$
    T  -> .aT  [ab] // Shift  on aa, ac,     go to (4)
    T  -> .c   [ab] // Shift  on ca,         go to (5)
    T  -> .    [ab] // Reduce on ab

(4)
    T  -> a.T  [$$] // Go to 6
    T  -> a.T  [ab] // Go to 6
    T  -> .    [$$] // Reduce on $$
    T  -> .aT  [$$] // Shift  on aa, ac, a$, go to (4)
    T  -> .c   [$$] // Shift  on c$,         go to (5)
    T  -> .    [ab] // Reduce on ab
    T  -> .aT  [ab] // Shift  on aa, ac,     go to (4)
    T  -> .c   [ab] // Shift  on ca,         go to (5)

(5)
    T  -> c.   [$$] // Reduce on $$
    T  -> c.   [ab] // Reduce on ab

(6)
    T  -> aT.  [$$] // Reduce on $$
    T  -> aT.  [ab] // Reduce on ab

(7)
    R  -> abT. [$$] // Reduce on $$
    R  -> abT. [ab] // Reduce on ab

(8)
    S  -> R.   [$$] // Reduce on $$
    S  -> R.S  [$$] // Go to 9
    S  -> .RS  [$$] // Go to 8
    S  -> .R   [$$] // Go to 8
    R  -> .abT [$$] // Shift  on ab, go to (2)
    R  -> .abT [ab] // Shift  on ab, go to (2)

(9)
    S  -> RS.  [$$] // Reduce on $$

(10)
    S' -> S.   [$$] // Accept on $$

So now we have our LR(2) parser for this grammar. All that's left to do now is to encode this as an action and goto table, along the lines of what we do for an LR(1) parser.

As you might expect, the action table for an LR(2) parser differs from that of the action table for an LR(1) parser in that it's keyed by lookaheads given by two characters rather than just one character. This means that the action table will be much larger for an LR(2) parser than an LR(1) parser. Here's what that looks like here:

 state | aa | ab | ac | a$ | ba | bb | bc | b$ | ca | cb | cc | c$ | $$
 ------+----+----+----+----+----+----+----+----+----+----+----+----+----
   1   |    | S  |    |    |    |    |    |    |    |    |    |    |
 ------+----+----+----+----+----+----+----+----+----+----+----+----+----
   2   |    |    |    |    | S  |    | S  | S  |    |    |    |    |
 ------+----+----+----+----+----+----+----+----+----+----+----+----+----
   3   | S  | R  | S  | S  |    |    |    |    | S  |    |    | S  | R
 ------+----+----+----+----+----+----+----+----+----+----+----+----+----
   4   | S  | R  | S  | S  |    |    |    |    | S  |    |    | S  | R
 ------+----+----+----+----+----+----+----+----+----+----+----+----+----
   5   |    | R  |    |    |    |    |    |    |    |    |    |    | R
 ------+----+----+----+----+----+----+----+----+----+----+----+----+----
   6   |    | R  |    |    |    |    |    |    |    |    |    |    | R
 ------+----+----+----+----+----+----+----+----+----+----+----+----+----
   7   |    | R  |    |    |    |    |    |    |    |    |    |    | R
 ------+----+----+----+----+----+----+----+----+----+----+----+----+----
   8   |    | S  |    |    |    |    |    |    |    |    |    |    | R
 ------+----+----+----+----+----+----+----+----+----+----+----+----+----
   9   |    |    |    |    |    |    |    |    |    |    |    |    | R
 ------+----+----+----+----+----+----+----+----+----+----+----+----+----
   10  |    |    |    |    |    |    |    |    |    |    |    |    | A

As you can see, each entry here just says whether to shift or reduce. In practice, each reduce item would be tagged with which production you'd actually do the reduction for, but, um, I was too lazy to type that out.

In an LR(1) parsing table, you'd typically combine this table with the "goto" table saying where to go after seeing each symbol. That's due to a fortuitous coincidence. In an LR(1) parser, the size of the lookahead is 1, which happens to align with the fact that the goto table says where you're supposed to transition to after seeing the next character. In an LR(2) parser, the decision about whether to shift or reduce depends on two characters of lookahead, but the choice of where to go next after reading one more character of the input only depends on a single character. That is, even though you have two tokens of lookahead to decide whether to do, you only shift one character over at a time. This means that the goto table for an LR(2) parser looks a lot like the goto table for an LR(0) or LR(1) parser, and is shown here:

 state |  a  |  b  |  c  |  $  |  S  |  R  |  T
-------+-----+-----+-----+-----+-----+-----+-----
   1   |  2  |     |     |     |  10 |  8  |
-------+-----+-----+-----+-----+-----+-----+-----
   2   |     |  3  |     |     |     |     |
-------+-----+-----+-----+-----+-----+-----+-----
   3   |  4  |     |  5  |     |     |     |  7
-------+-----+-----+-----+-----+-----+-----+-----
   4   |  4  |     |  5  |     |     |     |  6
-------+-----+-----+-----+-----+-----+-----+-----
   5   |     |     |     |     |     |     |
-------+-----+-----+-----+-----+-----+-----+-----
   6   |     |     |     |     |     |     |
-------+-----+-----+-----+-----+-----+-----+-----
   7   |     |     |     |     |     |     |
-------+-----+-----+-----+-----+-----+-----+-----
   8   |  2  |     |     |     |  9  |  8  |
-------+-----+-----+-----+-----+-----+-----+-----
   9   |     |     |     |     |     |     |
-------+-----+-----+-----+-----+-----+-----+-----
   10  |     |     |     |     |     |     |

So, to summarize:

The LR(2) parser uses two tokens of lookahead for each LR item. This means that we need to work with FIRST2 sets rather than FIRST sets, and introduces some new complexity when determining whether to shift or to reduce.

LR(2) parses have dot lookahead. For each shift item, we use the FIRST2 set to determine what characters can legally follow the dot from where we are, and shift on any of them.

The LR(2) action table is keyed by pairs of characters rather than single characters, but the goto table still is keyed by character.

Interestingly, once you know how to build an LR(2) parser, you can generalize the idea to build an LR(k) parser for any k ≥ 2. In particular, all the "new surprises" that arose here are the same ones that you'll see for larger and larger values of k.

In practice, LR(2) parsers are rarely used due to the size of their action tables and the fact that they generally have way more states than an LR(1) parser due to the increased lookaheads. But it's still worthwhile, IMHO, to see how to they work. It gives you a sense of how LR parsing works more generally.

Hope this helps!

A huge thanks to @AProgrammer's answer on cs.stackexchange.com about dot lookaheads versus item lookaheads, which helped me get a better sense of how dot lookaheads function and what their purpose is!

If you'd like to read the original paper on LR(k) parsing, which specs out the full rules for LR(k) parsing in full detail, check out "On the Translation of Languages from Left to Right" by Don Knuth.


来源: stackexchange

问:
Prolog permutation extracting solutions
```<code>permutation([], []).
permutation(L, [X|Xs]) :- select(X, L, Rest), permutation(Rest, Xs).
</code>```

If I type permutation([1,2,3],R), the first solution is "[1,2,3]" but how to get to the second one without using ";" or "fail". I need to use the 2nd solution like "[1,3,2]" or so in order compare it to another list.

What I mean is:

```<code>permutation([], []).
permutation(L, [X|Xs]) :- select(X, L, Rest), permutation(Rest, Xs).

go_perm(L,P) :-
        L = P,
        write(P),nl.

go_perm(L,P) :-
        permutation(P,P2), % in this case i wanna get the next solution -.-
        go_perm(L,P2).
</code>```

If L = P then it finishes. Permutation of the first solution for "[1,2,3]" is "[1,2,3]". But that pulls me into stackoverflow because it runs into never-endless thing.
Perhaps you understand me. Thanks!

答: permutation is a predicate that succeeds when one list is a permutation of the other. You don't actually need to enumerate them; just write permutation([1, 2, 3], [2, 1, 3]) and Prolog will tell you "true".

ContentLicense: CC BY-SA 3.0

Title: Prolog permutation extracting solutions

Body:
permutation([], []).
permutation(L, [X|Xs]) :- select(X, L, Rest), permutation(Rest, Xs).

If I type permutation([1,2,3],R), the first solution is "[1,2,3]" but how to get to the second one without using ";" or "fail". I need to use the 2nd solution like "[1,3,2]" or so in order compare it to another list.

What I mean is:

permutation([], []).
permutation(L, [X|Xs]) :- select(X, L, Rest), permutation(Rest, Xs).

go_perm(L,P) :-
        L = P,
        write(P),nl.

go_perm(L,P) :-
        permutation(P,P2), % in this case i wanna get the next solution -.-
        go_perm(L,P2).

If L = P then it finishes. Permutation of the first solution for "[1,2,3]" is "[1,2,3]". But that pulls me into stackoverflow because it runs into never-endless thing.
Perhaps you understand me. Thanks!


问:
How to start game of snake with key press event?
I have created a simple game of Snake using HTML 5 Canvas and JavaScript. I am nearly finished with the small project, however, I have one problem that I can't solve. On load, the game of snake automatically starts, usually resulting in a "Game Over", I would like for the player to be able to first press the direction they are wanting to go, and then the game will start. I have tried every way I can think possible to do this, mainly by using "keydown" or other similar event listeners. No matter where I put the code, nothing seems to work. Any ideas? Many thanks to anyone who takes the time out of their day to help me, it is greatly appreciated. Below, I will leave the code for the project for those wanting to help.

Snake game website: Snake Game

HTML/CSS:

window.onload = function () {
    var cvs = document.getElementById("canvas");
    var ctx = cvs.getContext("2d");

    var cvsW = cvs.width;
    var cvsH = cvs.height;

    var snakeW = 20;
    var snakeH = 20;

    let score = 0;

    var direction = "right";

    this.document.addEventListener("keydown", getDirection);

    function getDirection(e) {
        if (e.keyCode == 37 && direction != "right") {
            direction = "left";
        } else if (e.keyCode == 38 && direction != "down") {
            direction = "up";
        } else if (e.keyCode == 39 && direction != "left") {
            direction = "right";
        } else if (e.keyCode == 40 && direction != "up") {
            direction = "down";
        }
    }

    function drawSnake(x, y) {
        ctx.fillStyle = "#507786";
        ctx.fillRect(x * snakeW, y * snakeH, snakeW, snakeH);

        ctx.fillStyle = "#507786";
        ctx.strokeRect(x * snakeW, y * snakeH, snakeW, snakeH);
    }

    drawSnake(4, 5);

    var len = 4;
    var snake = [];

    for (var i = len - 1; i >= 0; i--) {
        snake.push({
            x: i,
            y: 0
        });
    }

   food = {
        x: Math.floor(Math.random() * (cvsW / snakeW - 1) + 1),
        y: Math.floor(Math.random() * (cvsH / snakeH - 1) + 1)
    }

    function drawFood(x, y) {
        ctx.fillStyle = "black";
        ctx.fillRect(x * snakeW, y * snakeH, snakeW, snakeH);

        ctx.fillStyle = "#507786";
        ctx.strokeRect(x * snakeW, y * snakeH, snakeW, snakeH);
    }

    function checkCollision(x,y,array) {
        for (var i = 0; i < array.length; i++) {
            if (x == array[i].x && y == array[i].y) {
                return true;
            }
        }
        return false;
    }

    function draw() {
        ctx.clearRect(0, 0, cvsW, cvsH);
        for (var i = 0; i < snake.length; i++) {
            var x = snake[i].x;
            var y = snake[i].y;
            drawSnake(x, y);
        }

        drawFood(food.x, food.y);

        var snakeX = snake[0].x;
        var snakeY = snake[0].y;

        if (direction == "left") snakeX--;
        else if (direction == "up") snakeY--;
        else if (direction == "right") snakeX++;
        else if (direction == "down") snakeY++;

        if (snakeX < 0 || snakeY < 0 || snakeX >= cvsW / snakeW || snakeY >= cvsH / snakeH
            || checkCollision(snakeX,snakeY,snake)) {
            snake = null;
            document.getElementById("gameover").innerHTML = "Game Over";
            setInterval(function(){
                location.reload();
            }, 3000);
        }

        if (snakeX == food.x && snakeY == food.y) {
            food = {
                x : Math.floor(Math.random() * (cvsW / snakeW -1) + 1),
                y : Math.floor(Math.random() * (cvsH / snakeH -1) + 1)
            }
            var newHead = {
                x : snakeX,
                y : snakeY
            };
            score += 1
            document.getElementById("gameScore").innerHTML = score;
        } else {
            snake.pop();
            var newHead = {
                x : snakeX,
                y : snakeY
            };
        }

        snake.unshift(newHead);
    }

    setInterval(draw, 60);

}```
<pre class="snippet-code-html lang-html prettyprint-override"><code><html>
<meta charset="UTF-8">
<title>
    Snake Game
</title>
<link href="https://fonts.googleapis.com/css?family=Sniglet&display=swap" rel="stylesheet">
<style>
    * {
        padding: 0px;
        margin: 0px;
    }

    #canvas {
        background-color: #8BAC0F;
        -webkit-box-shadow: 10px 10px 5px 0px rgba(0, 0, 0, 0.75);
        -moz-box-shadow: 10px 10px 5px 0px rgba(0, 0, 0, 0.75);
        box-shadow: 10px 10px 5px 0px rgba(0, 0, 0, 0.75);
    }

    #snakeGroup {
        text-align: center;
    }

    #snakeTitle {
        font-family: 'Sniglet', cursive;
        font-size: 80px;
        margin-top: 40px;
        margin-bottom: 20px;
    }

    #snakePara {
        font-family: 'Sniglet', cursive;
        font-size: 20px;
        margin-bottom: 20px;
    }

    #gameover {
        font-family: 'Sniglet', cursive;
        font-size: 50px;
        margin-bottom: 15px;
    }

    #footerText {
        font-family: 'Sniglet', cursive;
        font-size: 35px;
        margin-top: 25px;
    }
</style>

<body onkeypress="window.onload">
    <div id="snakeGroup">
        <h1 id="snakeTitle">Snake </h1>
        <p id="snakePara">Press the arrow keys ⬅⬆⬇➡ to move the snake.<br> Eat the food to score points. If the
            snake touches the walls
            or itself, its game over.<br> The game will automatically restart after 3 seconds. Happy Gaming!</p>
        <h2 id="gameover">Score: <span id="gameScore"></span></h2>
        <canvas id="canvas" width="500px" height="500px"></canvas>
        <h3 id="footerText">Made with ❤ by David Winters</h3>
    </div>

    <script src="snake.js"></script>
</body>

</html></code>```

答:
What if you initialize direction as "start"-

```<code>var direction = "start";
</code>```

then add this code in the draw function right after you initialize snakeX and snakeY-

```<code>    var snakeX = snake[0].x;
    var snakeY = snake[0].y;

    if (direction == "start")
    {
    snakeX =  snakeX*.0001;
    }
</code>```

Thus, the snake will initially be moving very slowly, and it will appear that the snake won't start moving unless you press "keydown".

I added the code in the code snippet.

window.onload = function () {
    var cvs = document.getElementById("canvas");
    var ctx = cvs.getContext("2d");

    var cvsW = cvs.width;
    var cvsH = cvs.height;

    var snakeW = 20;
    var snakeH = 20;

    let score = 0;

    var direction = "start";

    this.document.addEventListener("keydown", getDirection);

    function getDirection(e) {
        if (e.keyCode == 37 && direction != "right") {
            direction = "left";
        } else if (e.keyCode == 38 && direction != "down") {
            direction = "up";
        } else if (e.keyCode == 39 && direction != "left") {
            direction = "right";
        } else if (e.keyCode == 40 && direction != "up") {
            direction = "down";
        }
    }

    function drawSnake(x, y) {
        ctx.fillStyle = "#507786";
        ctx.fillRect(x * snakeW, y * snakeH, snakeW, snakeH);

        ctx.fillStyle = "#507786";
        ctx.strokeRect(x * snakeW, y * snakeH, snakeW, snakeH);
    }

    drawSnake(4, 5);

    var len = 4;
    var snake = [];

    for (var i = len - 1; i >= 0; i--) {
        snake.push({
            x: i,
            y: 0
        });
    }

   food = {
        x: Math.floor(Math.random() * (cvsW / snakeW - 1) + 1),
        y: Math.floor(Math.random() * (cvsH / snakeH - 1) + 1)
    }

    function drawFood(x, y) {
        ctx.fillStyle = "black";
        ctx.fillRect(x * snakeW, y * snakeH, snakeW, snakeH);

        ctx.fillStyle = "#507786";
        ctx.strokeRect(x * snakeW, y * snakeH, snakeW, snakeH);
    }

    function checkCollision(x,y,array) {
        for (var i = 0; i < array.length; i++) {
            if (x == array[i].x && y == array[i].y) {
                return true;
            }
        }
        return false;
    }

    function draw() {
        ctx.clearRect(0, 0, cvsW, cvsH);
        for (var i = 0; i < snake.length; i++) {
            var x = snake[i].x;
            var y = snake[i].y;
            drawSnake(x, y);
        }

        drawFood(food.x, food.y);

        var snakeX = snake[0].x;
        var snakeY = snake[0].y;

         if (direction == "start")
          {
          snakeX =  snakeX*.0001;
          }

        if (direction == "left") snakeX--;
        else if (direction == "up") snakeY--;
        else if (direction == "right") snakeX++;
        else if (direction == "down") snakeY++;

        if (snakeX < 0 || snakeY < 0 || snakeX >= cvsW / snakeW || snakeY >= cvsH / snakeH
            || checkCollision(snakeX,snakeY,snake)) {
            snake = null;
            document.getElementById("gameover").innerHTML = "Game Over";
            setInterval(function(){
                location.reload();
            }, 3000);
        }

        if (snakeX == food.x && snakeY == food.y) {
            food = {
                x : Math.floor(Math.random() * (cvsW / snakeW -1) + 1),
                y : Math.floor(Math.random() * (cvsH / snakeH -1) + 1)
            }
            var newHead = {
                x : snakeX,
                y : snakeY
            };
            score += 1
            document.getElementById("gameScore").innerHTML = score;
        } else {
            snake.pop();
            var newHead = {
                x : snakeX,
                y : snakeY
            };
        }

        snake.unshift(newHead);
    }

    setInterval(draw, 60);

}```
<pre class="snippet-code-html lang-html prettyprint-override"><code><html>
<meta charset="UTF-8">
<title>
    Snake Game
</title>
<link href="https://fonts.googleapis.com/css?family=Sniglet&display=swap" rel="stylesheet">
<style>
    * {
        padding: 0px;
        margin: 0px;
    }

    #canvas {
        background-color: #8BAC0F;
        -webkit-box-shadow: 10px 10px 5px 0px rgba(0, 0, 0, 0.75);
        -moz-box-shadow: 10px 10px 5px 0px rgba(0, 0, 0, 0.75);
        box-shadow: 10px 10px 5px 0px rgba(0, 0, 0, 0.75);
    }

    #snakeGroup {
        text-align: center;
    }

    #snakeTitle {
        font-family: 'Sniglet', cursive;
        font-size: 80px;
        margin-top: 40px;
        margin-bottom: 20px;
    }

    #snakePara {
        font-family: 'Sniglet', cursive;
        font-size: 20px;
        margin-bottom: 20px;
    }

    #gameover {
        font-family: 'Sniglet', cursive;
        font-size: 50px;
        margin-bottom: 15px;
    }

    #footerText {
        font-family: 'Sniglet', cursive;
        font-size: 35px;
        margin-top: 25px;
    }
</style>

<body onkeypress="window.onload">
    <div id="snakeGroup">
        <h1 id="snakeTitle">Snake </h1>
        <p id="snakePara">Press the arrow keys ⬅⬆⬇➡ to move the snake.<br> Eat the food to score points. If the
            snake touches the walls
            or itself, its game over.<br> The game will automatically restart after 3 seconds. Happy Gaming!</p>
        <h2 id="gameover">Score: <span id="gameScore"></span></h2>
        <canvas id="canvas" width="500px" height="500px"></canvas>
        <h3 id="footerText">Made with ❤ by David Winters</h3>
    </div>

    <script src="snake.js"></script>
</body>

</html></code>```

ContentLicense: CC BY-SA 4.0

Body:
I have created a simple game of Snake using HTML 5 Canvas and JavaScript. I am nearly finished with the small project, however, I have one problem that I can't solve. On load, the game of snake automatically starts, usually resulting in a "Game Over", I would like for the player to be able to first press the direction they are wanting to go, and then the game will start. I have tried every way I can think possible to do this, mainly by using "keydown" or other similar event listeners. No matter where I put the code, nothing seems to work. Any ideas? Many thanks to anyone who takes the time out of their day to help me, it is greatly appreciated. Below, I will leave the code for the project for those wanting to help.

Snake game website: Snake Game

HTML/CSS:

window.onload = function () {
    var cvs = document.getElementById("canvas");
    var ctx = cvs.getContext("2d");

    var cvsW = cvs.width;
    var cvsH = cvs.height;

    var snakeW = 20;
    var snakeH = 20;

    let score = 0;

    var direction = "right";

    this.document.addEventListener("keydown", getDirection);

    function getDirection(e) {
        if (e.keyCode == 37 && direction != "right") {
            direction = "left";
        } else if (e.keyCode == 38 && direction != "down") {
            direction = "up";
        } else if (e.keyCode == 39 && direction != "left") {
            direction = "right";
        } else if (e.keyCode == 40 && direction != "up") {
            direction = "down";
        }
    }

    function drawSnake(x, y) {
        ctx.fillStyle = "#507786";
        ctx.fillRect(x * snakeW, y * snakeH, snakeW, snakeH);

        ctx.fillStyle = "#507786";
        ctx.strokeRect(x * snakeW, y * snakeH, snakeW, snakeH);
    }

    drawSnake(4, 5);

    var len = 4;
    var snake = [];

    for (var i = len - 1; i >= 0; i--) {
        snake.push({
            x: i,
            y: 0
        });
    }

   food = {
        x: Math.floor(Math.random() * (cvsW / snakeW - 1) + 1),
        y: Math.floor(Math.random() * (cvsH / snakeH - 1) + 1)
    }

    function drawFood(x, y) {
        ctx.fillStyle = "black";
        ctx.fillRect(x * snakeW, y * snakeH, snakeW, snakeH);

        ctx.fillStyle = "#507786";
        ctx.strokeRect(x * snakeW, y * snakeH, snakeW, snakeH);
    }

    function checkCollision(x,y,array) {
        for (var i = 0; i < array.length; i++) {
            if (x == array[i].x && y == array[i].y) {
                return true;
            }
        }
        return false;
    }

    function draw() {
        ctx.clearRect(0, 0, cvsW, cvsH);
        for (var i = 0; i < snake.length; i++) {
            var x = snake[i].x;
            var y = snake[i].y;
            drawSnake(x, y);
        }

        drawFood(food.x, food.y);

        var snakeX = snake[0].x;
        var snakeY = snake[0].y;

        if (direction == "left") snakeX--;
        else if (direction == "up") snakeY--;
        else if (direction == "right") snakeX++;
        else if (direction == "down") snakeY++;

        if (snakeX < 0 || snakeY < 0 || snakeX >= cvsW / snakeW || snakeY >= cvsH / snakeH
            || checkCollision(snakeX,snakeY,snake)) {
            snake = null;
            document.getElementById("gameover").innerHTML = "Game Over";
            setInterval(function(){
                location.reload();
            }, 3000);
        }

        if (snakeX == food.x && snakeY == food.y) {
            food = {
                x : Math.floor(Math.random() * (cvsW / snakeW -1) + 1),
                y : Math.floor(Math.random() * (cvsH / snakeH -1) + 1)
            }
            var newHead = {
                x : snakeX,
                y : snakeY
            };
            score += 1
            document.getElementById("gameScore").innerHTML = score;
        } else {
            snake.pop();
            var newHead = {
                x : snakeX,
                y : snakeY
            };
        }

        snake.unshift(newHead);
    }

    setInterval(draw, 60);

}

<meta charset="UTF-8">
<title>
    Snake Game
</title>
<link href="https://fonts.googleapis.com/css?family=Sniglet&display=swap" rel="stylesheet">

Snake

Press the arrow keys ⬅⬆⬇➡ to move the snake.
 Eat the food to score points. If the
            snake touches the walls
            or itself, its game over.
 The game will automatically restart after 3 seconds. Happy Gaming!

Score:

        <canvas id="canvas" width="500px" height="500px"></canvas>

Made with ❤ by David Winters

Body:
What if you initialize direction as "start"-

var direction = "start";

then add this code in the draw function right after you initialize snakeX and snakeY-

    var snakeX = snake[0].x;
    var snakeY = snake[0].y;

    if (direction == "start")
    {
    snakeX =  snakeX*.0001;
    }

Thus, the snake will initially be moving very slowly, and it will appear that the snake won't start moving unless you press "keydown".

I added the code in the code snippet.

window.onload = function () {
    var cvs = document.getElementById("canvas");
    var ctx = cvs.getContext("2d");

    var cvsW = cvs.width;
    var cvsH = cvs.height;

    var snakeW = 20;
    var snakeH = 20;

    let score = 0;

    var direction = "start";

    this.document.addEventListener("keydown", getDirection);

    function getDirection(e) {
        if (e.keyCode == 37 && direction != "right") {
            direction = "left";
        } else if (e.keyCode == 38 && direction != "down") {
            direction = "up";
        } else if (e.keyCode == 39 && direction != "left") {
            direction = "right";
        } else if (e.keyCode == 40 && direction != "up") {
            direction = "down";
        }
    }

    function drawSnake(x, y) {
        ctx.fillStyle = "#507786";
        ctx.fillRect(x * snakeW, y * snakeH, snakeW, snakeH);

        ctx.fillStyle = "#507786";
        ctx.strokeRect(x * snakeW, y * snakeH, snakeW, snakeH);
    }

    drawSnake(4, 5);

    var len = 4;
    var snake = [];

    for (var i = len - 1; i >= 0; i--) {
        snake.push({
            x: i,
            y: 0
        });
    }

   food = {
        x: Math.floor(Math.random() * (cvsW / snakeW - 1) + 1),
        y: Math.floor(Math.random() * (cvsH / snakeH - 1) + 1)
    }

    function drawFood(x, y) {
        ctx.fillStyle = "black";
        ctx.fillRect(x * snakeW, y * snakeH, snakeW, snakeH);

        ctx.fillStyle = "#507786";
        ctx.strokeRect(x * snakeW, y * snakeH, snakeW, snakeH);
    }

    function checkCollision(x,y,array) {
        for (var i = 0; i < array.length; i++) {
            if (x == array[i].x && y == array[i].y) {
                return true;
            }
        }
        return false;
    }

    function draw() {
        ctx.clearRect(0, 0, cvsW, cvsH);
        for (var i = 0; i < snake.length; i++) {
            var x = snake[i].x;
            var y = snake[i].y;
            drawSnake(x, y);
        }

        drawFood(food.x, food.y);

        var snakeX = snake[0].x;
        var snakeY = snake[0].y;

         if (direction == "start")
          {
          snakeX =  snakeX*.0001;
          }

        if (direction == "left") snakeX--;
        else if (direction == "up") snakeY--;
        else if (direction == "right") snakeX++;
        else if (direction == "down") snakeY++;

        if (snakeX < 0 || snakeY < 0 || snakeX >= cvsW / snakeW || snakeY >= cvsH / snakeH
            || checkCollision(snakeX,snakeY,snake)) {
            snake = null;
            document.getElementById("gameover").innerHTML = "Game Over";
            setInterval(function(){
                location.reload();
            }, 3000);
        }

        if (snakeX == food.x && snakeY == food.y) {
            food = {
                x : Math.floor(Math.random() * (cvsW / snakeW -1) + 1),
                y : Math.floor(Math.random() * (cvsH / snakeH -1) + 1)
            }
            var newHead = {
                x : snakeX,
                y : snakeY
            };
            score += 1
            document.getElementById("gameScore").innerHTML = score;
        } else {
            snake.pop();
            var newHead = {
                x : snakeX,
                y : snakeY
            };
        }

        snake.unshift(newHead);
    }

    setInterval(draw, 60);

}

<html>
<meta charset="UTF-8">
<title>
    Snake Game
</title>
<link href="https://fonts.googleapis.com/css?family=Sniglet&display=swap" rel="stylesheet">
<style>
    * {
        padding: 0px;
        margin: 0px;
    }

    #canvas {
        background-color: #8BAC0F;
        -webkit-box-shadow: 10px 10px 5px 0px rgba(0, 0, 0, 0.75);
        -moz-box-shadow: 10px 10px 5px 0px rgba(0, 0, 0, 0.75);
        box-shadow: 10px 10px 5px 0px rgba(0, 0, 0, 0.75);
    }

    #snakeGroup {
        text-align: center;
    }

    #snakeTitle {
        font-family: 'Sniglet', cursive;
        font-size: 80px;
        margin-top: 40px;
        margin-bottom: 20px;
    }

    #snakePara {
        font-family: 'Sniglet', cursive;
        font-size: 20px;
        margin-bottom: 20px;
    }

    #gameover {
        font-family: 'Sniglet', cursive;
        font-size: 50px;
        margin-bottom: 15px;
    }

    #footerText {
        font-family: 'Sniglet', cursive;
        font-size: 35px;
        margin-top: 25px;
    }
</style>

<body onkeypress="window.onload">
    <div id="snakeGroup">
        <h1 id="snakeTitle">Snake </h1>
        <p id="snakePara">Press the arrow keys ⬅⬆⬇➡ to move the snake.<br> Eat the food to score points. If the
            snake touches the walls
            or itself, its game over.<br> The game will automatically restart after 3 seconds. Happy Gaming!</p>
        <h2 id="gameover">Score: <span id="gameScore"></span></h2>
        <canvas id="canvas" width="500px" height="500px"></canvas>
        <h3 id="footerText">Made with ❤ by David Winters</h3>
    </div>

    <script src="snake.js"></script>
</body>

</html>


问:
Using google sheets as a database authenticating from the code
I am working on a POC (a Vue based web application) for which I require a database. I want to use the google sheet as a database

I followed the official Google Sheets API v4 documentation and I am able to perform all kinds of database operations on the google sheet. But, it requires the user to explicitly click on a button and sign in to authenticate. I want it to be done from the code itself.

I have the following keys which are required along with the user consent to use the google sheets API

```<code>// Client ID and API key from the Developer Console
var CLIENT_ID = '<YOUR_CLIENT_ID>';
var API_KEY = '<YOUR_API_KEY>';
</code>```

Apart from this I also have a client secret which I have absolutely no idea how to use it in the code. From what I have read over the internet and what I have understood, it is used to authenticate the access to google sheets API from the code. But, I don't know how.

I did come across some of the third-party services like Sheetsu and SheetDB which I don't want to use. So, is there a way I can use google sheets as a database for simple CRUD operations just as we will do with any traditional database?

答:
It is behaving that way - expecting a user to authenticate - because you are using OAuth2 authentication which is meant for scenarios where a user grants your program access to their spreadsheet.

For your scenario you want to use the other type of authentication: service account.

Actually, you can use a service account with OAuth, as described here:

Using OAuth 2.0 for Server to Server Applications
https://developers.google.com/identity/protocols/oauth2/service-account

And you could consider this because the code examples tend to use OAuth, but I'm suggesting that you instead go back to the sheets API in the console:

https://console.cloud.google.com/apis/api/sheets.googleapis.com/credentials?project=yourProjectId

And click 'create credentials' and choose a service account instead of OAuth.  This method  has a simpler authentication flow since it is meant for your scenario: no end-user.

Also, I haven't done this in a while, but I think I took the service account client_email (the email address of the account - the main identifier) and give it permission to access the sheet, ie. share your sheet with it.

Finally, I would note - and you probably already know this - but you mention using sheets like a database and it doesn't have the performance characteristics for this.  It is more like a CRM: eg. suitable for a building a static site.

Body:
I am working on a POC (a Vue based web application) for which I require a database. I want to use the google sheet as a database

I followed the official Google Sheets API v4 documentation and I am able to perform all kinds of database operations on the google sheet. But, it requires the user to explicitly click on a button and sign in to authenticate. I want it to be done from the code itself.

I have the following keys which are required along with the user consent to use the google sheets API

// Client ID and API key from the Developer Console
var CLIENT_ID = '<YOUR_CLIENT_ID>';
var API_KEY = '<YOUR_API_KEY>';

Apart from this I also have a client secret which I have absolutely no idea how to use it in the code. From what I have read over the internet and what I have understood, it is used to authenticate the access to google sheets API from the code. But, I don't know how.

I did come across some of the third-party services like Sheetsu and SheetDB which I don't want to use. So, is there a way I can use google sheets as a database for simple CRUD operations just as we will do with any traditional database?


问:
How can I implement angularjs in quarkus restAPI
Built my first restful application using quarkus. I want to have a frontend which can call these restful services. any pointers. </p>

答:
You can use axios. And integrate with your preferred frontend technology.

Here is a reference.


问:
Why on react history createHashHistory appends /# for each path?
I have an application with this config for history:

import { createHashHistory } from 'history';
import { ConnectedRouter } from 'connected-react-router';

const history = createHashHistory({
  hashType: 'slash',
});
    ...
  <ConnectedRouter history={history}>
    <App />
  </ConnectedRouter>
```

But all my routes get appended by /#
ex: localhost:8080/ becomes: localhost:8080/#/

I already tried to update my packages as this question say but it didn't work.

The only thing that worked was change createHashHistory to createBrowserHistory, but I'm not sure what's the difference between them, and why createHashHistory is appending the /#

答:
With hashHistory, it produces url like
http://yourwebsite.net/#page/xxx

With browserHistory, it produces url like
http://yourwebsite.net/page/xxx

Which one to use? In real-world products, browserHistory is mostly used. A rule of thumb is "if you are using a dynamic server that can handle dynamic URLs then you need to use the BrowserRouter component but if you are using a server that only serves static files then a HashRouter component is what to be used in this case."

In your code, hashType: 'slash' is just the default value.

Body:
I have an application with this config for history:

import { createHashHistory } from 'history';
import { ConnectedRouter } from 'connected-react-router';

const history = createHashHistory({
  hashType: 'slash',
});
    ...
  <ConnectedRouter history={history}>
    <App />
  </ConnectedRouter>

But all my routes get appended by /#
ex: localhost:8080/ becomes: localhost:8080/#/

I already tried to update my packages as this question say but it didn't work.

The only thing that worked was change createHashHistory to createBrowserHistory, but I'm not sure what's the difference between them, and why createHashHistory is appending the /#


问:
difference between a pointer and reference parameter?
Are these the same:

```<code>int foo(bar* p) {
  return p->someInt();
}
</code>```

and

```<code>int foo(bar& r) {
  return r.someInt();
}
</code>```

Ignore the null pointer potential. Are these two functions functionally identical no matter if someInt() is virtual or if they are passed a bar or a subclass of bar?

Does this slice anything:

```<code>bar& ref = *ptr_to_bar;
</code>```

答:
As everyone else has mentioned, in implementation references and pointers are largely the same. There are some minor caveats:

You can't assign NULL to a reference
(shoosh mentioned this): that's
significant since there is no
"undefined" or "invalid" reference
value.

You can pass a temporary
variable as a const reference,
but it's not legal to pass a pointer
to a temporary.

For example, this is okay:

```<code>class Thingy; // assume a constructor Thingy(int,int)
void foo(const Thingy &a)
{
   a.DoSomething();
}

void bar( )
{
  foo( Thingy(1,2) );
}
</code>```

but most compilers will complain about

```<code>void foo2( Thingy * a);

void bar2()
{
  foo( &Thingy(1,2) );
}
</code>```

Taking the address of a variable to get a pointer forces the compiler to save it to memory. Assigning a reference to a local variable just creates a synonym; in some cases this may allow the compiler to keep the data on the register and avoid a load-hit-store. However, this only applies to local variables -- once something is passed as a parameter by reference, there's no avoiding saving it to stack.

```<code>void foo()
{
   int a = 5;
   // this may be slightly more efficient
   int &b = a;
   printf( "%d", ++b );
   // than this
   int *c = &a;
   printf( "%d", ++(*c) );
}
</code>```

Similarly, the __restrict keyword cannot be applied to references, only pointers.

You can't do pointer arithmetic with references, so whereas if you have a pointer into an array then the next element in the array can be had through p+1, a reference only ever points at one thing in its entire life.

Body:
Are these the same:

int foo(bar* p) {
  return p->someInt();
}

and

int foo(bar& r) {
  return r.someInt();
}

Ignore the null pointer potential. Are these two functions functionally identical no matter if someInt() is virtual or if they are passed a bar or a subclass of bar?

Does this slice anything:

bar& ref = *ptr_to_bar;

Body:
As everyone else has mentioned, in implementation references and pointers are largely the same. There are some minor caveats:

You can't assign NULL to a reference
(shoosh mentioned this): that's
significant since there is no
"undefined" or "invalid" reference
value.

You can pass a temporary
variable as a const reference,
but it's not legal to pass a pointer
to a temporary.

For example, this is okay:

class Thingy; // assume a constructor Thingy(int,int)
void foo(const Thingy &a)
{
   a.DoSomething();
}

void bar( )
{
  foo( Thingy(1,2) );
}

but most compilers will complain about

void foo2( Thingy * a);

void bar2()
{
  foo( &Thingy(1,2) );
}

Taking the address of a variable to get a pointer forces the compiler to save it to memory. Assigning a reference to a local variable just creates a synonym; in some cases this may allow the compiler to keep the data on the register and avoid a load-hit-store. However, this only applies to local variables -- once something is passed as a parameter by reference, there's no avoiding saving it to stack.

void foo()
{
   int a = 5;
   // this may be slightly more efficient
   int &b = a;
   printf( "%d", ++b );
   // than this
   int *c = &a;
   printf( "%d", ++(*c) );
}

Similarly, the __restrict keyword cannot be applied to references, only pointers.

You can't do pointer arithmetic with references, so whereas if you have a pointer into an array then the next element in the array can be had through p+1, a reference only ever points at one thing in its entire life.

OwnerDisplayName: Crashworks

ContentLicense: CC BY-SA 2.5


问:
With rspec, can I mock an object that is inside the method I am testing?
I have defined the following method:

```<code>def some_method

  x = x + 1
  y = some_other_method(x)

  x + y
end
</code>```

Now in my rspec spec, can I mock the call to some_other_method for my unit test for some_method?

答:
You can indeed mock out other methods in a RSpec test. If the two methods you mentioned are inside a class, Foo, you would do something like this to make sure that some_other_method is called:

```<code>subject{ Foo.new }
it "should do whatever you're testing" do
  subject.should_receive(:some_other_method).and_return(5)
  subject.some_method
end
</code>```

If you don't need to assert that is was called, just assert the results of some_method, you can do something like this instead:

```<code>subject{ Foo.new }
it "should do whatever you're testing" do
  subject.stub(:some_other_method).and_return(5)
  subject.some_method.should eq(6)
end
</code>```

The above examples assume you're using RSpec 2. If you're using RSpec 1, you'll need to use stubs instead of stub.

If your methods are defined outside of a class, they're really defined on the class Object, so just use Object instead of Foo in the examples above.

For more information about mocks in RSpec, check out http://relishapp.com/rspec/rspec-mocks for RSpec 2 or http://rspec.info/documentation/mocks/ for RSpec 1.

Body:
I have defined the following method:

def some_method

  x = x + 1
  y = some_other_method(x)

  x + y
end

Now in my rspec spec, can I mock the call to some_other_method for my unit test for some_method?

Body:
You can indeed mock out other methods in a RSpec test. If the two methods you mentioned are inside a class, Foo, you would do something like this to make sure that some_other_method is called:

subject{ Foo.new }
it "should do whatever you're testing" do
  subject.should_receive(:some_other_method).and_return(5)
  subject.some_method
end

If you don't need to assert that is was called, just assert the results of some_method, you can do something like this instead:

subject{ Foo.new }
it "should do whatever you're testing" do
  subject.stub(:some_other_method).and_return(5)
  subject.some_method.should eq(6)
end

The above examples assume you're using RSpec 2. If you're using RSpec 1, you'll need to use stubs instead of stub.

If your methods are defined outside of a class, they're really defined on the class Object, so just use Object instead of Foo in the examples above.

For more information about mocks in RSpec, check out http://relishapp.com/rspec/rspec-mocks for RSpec 2 or http://rspec.info/documentation/mocks/ for RSpec 1.


问:
CSS width/height issue
I am facing a problem with image height. I want to make that image 100% height without hard coding. But i can't do that. Every time some margin goes bottom to the image. I have changed the image width, height, font size but nothing works.

Here is an example of the image not filling the height:

* {
  margin: 0;
  padding: 0;
  outline: none;
  box-sizing: border-box;
}
html {
  font-size:16px;
}
body {
  font-family: Raleway, "Times New Roman", Times, serif;
  background-color: #f6f6f6;
  line-height: 1.5rem;
  width: 100%;
  color: #424242;
}

.flexbox {
  display: flex;
  justify-content: space-between;
}

.img-responsive {max-width:100%;max-height:100%;}
.card {
  background-color: #ffffff;
  border: 2px solid red;
  margin: 1.5rem 0rem 0rem;
  width: 75%;
}

.post-card-body {
  padding: 1.5rem;
}

.post-card-heading {
  margin: 0 0 0.75rem;
}

.btn-section {
  margin-top: 1rem;
}
.continue-btn {
  background-color: #ffb69b;
  border-color: #ffb69b;
}

.btn {
  font-size: 0.75rem;
  text-transform: uppercase;
  color: #ffffff;
  padding: 0.75rem 1.25rem;
  border: 0.0625rem solid #e9e9ea;
}```
<pre class="snippet-code-html lang-html prettyprint-override"><code><div class="flexbox card">
  <div class="post-card-img">
    <img src="http://via.placeholder.com/300x300/DDaDaa/FFFFFF" alt="" class="img-responsive" />
  </div>
  <div class="post-card-body">
    <div class="post-card-heading">
      <h3>Lorem ipsum dolor sit amet.</h3>
      <h6>By Admin Ahsan September 11, 2015</h6>
      <hr />
    </div>
    <p>
      Lorem ipsum dolor sit amet consectetur adipisicing elit. Harum
      atque sed in, fugiat natus laboriosam
    </p>
    <div class="btn-section">
      <button class="btn continue-btn">Continue Reading</button>
    </div>
  </div>
</div></code>```

codepen link: click here
Screenshot: click here

答: Add display:block to your image. It's being treated as an inline element which doesn't have a height.</p>

Title: CSS width/height issue

Body:
I am facing a problem with image height. I want to make that image 100% height without hard coding. But i can't do that. Every time some margin goes bottom to the image. I have changed the image width, height, font size but nothing works.

Here is an example of the image not filling the height:

* {
  margin: 0;
  padding: 0;
  outline: none;
  box-sizing: border-box;
}
html {
  font-size:16px;
}
body {
  font-family: Raleway, "Times New Roman", Times, serif;
  background-color: #f6f6f6;
  line-height: 1.5rem;
  width: 100%;
  color: #424242;
}

.flexbox {
  display: flex;
  justify-content: space-between;
}

.img-responsive {max-width:100%;max-height:100%;}
.card {
  background-color: #ffffff;
  border: 2px solid red;
  margin: 1.5rem 0rem 0rem;
  width: 75%;
}

.post-card-body {
  padding: 1.5rem;
}

.post-card-heading {
  margin: 0 0 0.75rem;
}

.btn-section {
  margin-top: 1rem;
}
.continue-btn {
  background-color: #ffb69b;
  border-color: #ffb69b;
}

.btn {
  font-size: 0.75rem;
  text-transform: uppercase;
  color: #ffffff;
  padding: 0.75rem 1.25rem;
  border: 0.0625rem solid #e9e9ea;
}

Lorem ipsum dolor sit amet.

By Admin Ahsan September 11, 2015

      Lorem ipsum dolor sit amet consectetur adipisicing elit. Harum
      atque sed in, fugiat natus laboriosam

      <button class="btn continue-btn">Continue Reading</button>

codepen link: click here
Screenshot: click here


问:
MS Graph API: is it possible to order mail messages by recipient(s)?
To tell the truth, I am a bit surprised I've failed to google the answer (not for MS Graph API, neither for MS Outlook REST API) - it looks like I am the only one who is faced the task to order the mail messages (for example, in Sent Items folder) by recipient.

In the manual, I see it is possible to order messages by sender; I can request something like

GET https://graph.microsoft.com/v1.0/me/messages?$orderby=from/emailAddress/address

or

GET https://graph.microsoft.com/v1.0/me/messages?$orderby=from/emailAddress/name,from/emailAddress/address

But what with the recipients, which are actually an array (even 3 arrays: toRecipients, ccRecipients and bccRecipients)?

I've tried all API requests I could imagine, but got only errors. Am I missing something?

答: Order by collections is not supported. Maybe, if recipients are well known, you can filter by them and do client side sorting. Not the most efficient but might do the job.</p>


问:
I build an app in Android Studio i made it apk then installed in phone
i can not open that app after installation i get summary error:
java.lang.RuntimeException: Canvas: trying to draw too large(127844352bytes) bitmap.
    at android.view.DisplayListCanvas.throwIfCannotDraw(DisplayListCanvas.java:229)
    at android.view.RecordingCanvas.drawBitmap(RecordingCanvas.java:97)
    at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:529)
    at android.widget.ImageView.onDraw(ImageView.java:1367)
    at android.view.View.draw(View.java:19218)
    at android.view.View.updateDisplayListIfDirty(View.java:18168)
    at android.view.View.draw(View.java:18946)
    at android.view.ViewGroup.drawChild(ViewGroup.java:4240)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4024)
    at androidx.constraintlayout.widget.ConstraintLayout.dispatchDraw(ConstraintLayout.java:2023)
    at android.view.View.draw(View.java:19221)
    at android.view.View.updateDisplayListIfDirty(View.java:18168)
    at android.view.View.draw(View.java:18946)
    at android.view.ViewGroup.drawChild(ViewGroup.java:4240)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4024)
    at android.view.View.updateDisplayListIfDirty(View.java:18159)
    at android.view.View.draw(View.java:18946)
    at android.view.ViewGroup.drawChild(ViewGroup.java:4240)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4024)
    at android.view.View.updateDisplayListIfDirty(View.java:18159)
    at android.view.View.draw(View.java:18946)
    at android.view.ViewGroup.drawChild(ViewGroup.java:4240)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4024)
    at android.view.View.updateDisplayListIfDirty(View.java:18159)
    at android.view.View.draw(View.java:18946)
    at android.view.ViewGroup.drawChild(ViewGroup.java:4240)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4024)
    at android.view.View.updateDisplayListIfDirty(View.java:18159)
    at android.view.View.draw(View.java:18946)
    at android.view.ViewGroup.drawChild(ViewGroup.java:4240)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4024)
    at android.view.View.draw(View.java:19221)
    at com.android.internal.policy.DecorView.draw(DecorView.java:791)
    at android.view.View.updateDisplayListIfDirty(View.java:18168)
    at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:685)
    at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:691)
    at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:799)
    at android.view.ViewRootImpl.draw(ViewRootImpl.java:3056)
    at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2851)
    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2404)
    at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1437)
    at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6886)
    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1029)
    at android.view.Choreographer.doCallbacks(Choreographer.java:841)
    at android.view.Choreographer.doFrame(Choreographer.java:772)
    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1015)
    at android.os.Handler.handleCallback(Handler.java:794)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:176)
    at android.app.ActivityThread.main(ActivityThread.java:6651)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:824)</p>

答:
From the description of the error, I guess some components in your projects aren't properly laid out. </p>

<p>E.g Text Field overflowing its required layout and so on. </p>

Body:
From the description of the error, I guess some components in your projects aren't properly laid out.

E.g Text Field overflowing its required layout and so on.


问:
Accessing outer loop variable from inside loop in Java
My list consist of list character definition like List<Character> listCharacter = new ArrayList<Character>();

Character class:

```<code>private List<Result> results;
</code>```

Result Class :

```<code> private int id;

 private String name;
</code>```

I am trying to iterate over listCharacter like

```<code>listCharacter.forEach((characters) -> {

            characters.getResults().forEach((result) -> {

                if (result.getId() == id) {
                    return result;
                }

            });
        });
</code>```

But when am trying this i got foreach not applicable the type Iterable is not applicable for the arguments (( result) -> {}) error . I know chain loop not possible with foreach loop.

Also i know we can use consumers like duplicate question solutions.But then  i can't reach outer loop variable inside inner loop.The Consumer classes just using it and disposing it.Therefore I don't wanna use that.

How can i do this i mean reaching outer loop variable inside inner loop without dealing with this such errors?

TLDR: I have 2 list objects. I am iterating over outer one(listCharacter) that who has inner one list object(result) which has id and name.If the id matched the method would return.That's all.

答:
I would firstly suggest that you avoid calling a custom class Character as that's already in use by the Java API. you don't have to but it would avoid confusion here and there. Consider remaining to something more meaningful and reflecting of what the class does.

Also note that you cannot return a result from forEach.

You can accomplish your intended result as follows:

```<code>source.stream()
      .map(Character::getResults)
      .flatMap(Collection::stream)
      .filter(s -> s.getId() == id)
      .findFirst().orElse(null);
</code>```

Body:
My list consist of list character definition like List<Character> listCharacter = new ArrayList<Character>();

Character class:

private List<Result> results;

Result Class :

 private int id;

 private String name;

I am trying to iterate over listCharacter like

listCharacter.forEach((characters) -> {

            characters.getResults().forEach((result) -> {

                if (result.getId() == id) {
                    return result;
                }

            });
        });

But when am trying this i got foreach not applicable the type Iterable is not applicable for the arguments (( result) -> {}) error . I know chain loop not possible with foreach loop.

Also i know we can use consumers like duplicate question solutions.But then  i can't reach outer loop variable inside inner loop.The Consumer classes just using it and disposing it.Therefore I don't wanna use that.

How can i do this i mean reaching outer loop variable inside inner loop without dealing with this such errors?

TLDR: I have 2 list objects. I am iterating over outer one(listCharacter) that who has inner one list object(result) which has id and name.If the id matched the method would return.That's all.

Body:
I would firstly suggest that you avoid calling a custom class Character as that's already in use by the Java API. you don't have to but it would avoid confusion here and there. Consider remaining to something more meaningful and reflecting of what the class does.

Also note that you cannot return a result from forEach.

You can accomplish your intended result as follows:

source.stream()
      .map(Character::getResults)
      .flatMap(Collection::stream)
      .filter(s -> s.getId() == id)
      .findFirst().orElse(null);


问:
Adding red dot for means of each class in ggplot
I have the following basic plot.

```<code>ggplot(mpg) +
geom_jitter(aes(x = class, y = hwy))
+   stat_summary(aes(x = class, y = hwy),fun=mean(), geom = “point”, color="red")
</code>```

Im trying to add red dots for the means of hwy for each class.

But i am getting the following error:

```<code>Error: unexpected input in "+   stat_summary(aes(x = class, y = hwy),fun=mean(), geom = “"
</code>```

答:
Based on the input showed,  the + is showed at the beginning of third line, while the command ended at 2nd line.  It should be at the end of second line.  Also, there was fancy quotes around the point and fun = mean is enough

```<code>library(ggplot2)
ggplot(mpg) +
   geom_jitter(aes(x = class, y = hwy)) +
   stat_summary(aes(x = class, y = hwy),fun=mean, geom = "point", color="red")
</code>```

-output

Body:
I have the following basic plot.

ggplot(mpg) +
geom_jitter(aes(x = class, y = hwy))
+   stat_summary(aes(x = class, y = hwy),fun=mean(), geom = “point”, color="red")

Im trying to add red dots for the means of hwy for each class.

But i am getting the following error:

Error: unexpected input in "+   stat_summary(aes(x = class, y = hwy),fun=mean(), geom = “"

Body:
Based on the input showed,  the + is showed at the beginning of third line, while the command ended at 2nd line.  It should be at the end of second line.  Also, there was fancy quotes around the point and fun = mean is enough

library(ggplot2)
ggplot(mpg) +
   geom_jitter(aes(x = class, y = hwy)) +
   stat_summary(aes(x = class, y = hwy),fun=mean, geom = "point", color="red")

-output


问:
Add column to existing dataframe and import data into new column in Python Pandas
I am reading a CSV file into a pandas dataframe using Python. I want to read in a list of text files into a new column of the dataframe.

The original CSV file I'm reading from looks like this:

```<code>Name,PrivateIP
bastion001,10.238.2.166
logicmonitor001,10.238.2.52
logicmonitor002,45.21.2.13
</code>```

The original dataframe looks like this.

code:

```<code>hosts_list = dst = os.path.join('..', '..', 'source_files', 'aws_hosts_list', 'aws_hosts_list.csv')
fields = ["Name", "PrivateIP"]
orig_df = pd.read_csv(hosts_list, skipinitialspace=True, usecols=fields)
print(f"Orig DF: {orig_df}")
</code>```

output:

```<code>Orig DF:
                       Name     PrivateIP
0               bastion001  10.238.2.166
1          logicmonitor001   10.238.2.52
2         logicmonitor002    45.21.2.13
</code>```

The text directory has a bunch of text files in it with memory readings in each:

```<code>bastion001-memory.txt              B-mmp-rabbitmq-core002-memory.txt  logicmonitor002-memory.txt    mmp-cassandra001-memory.txt  company-division-rcsgw002-memory.txt
B-mmp-platsvc-core001-memory.txt   haproxy001-memory.txt              company-cassandra001-memory.txt  mmp-cassandra002-memory.txt  company-waepd001-memory.txt
B-mmp-platsvc-core002-memory.txt   haproxy002-memory.txt              company-cassandra002-memory.txt  mmp-cassandra003-memory.txt  company-waepd002-memory.txt
B-mmp-rabbitmq-core001-memory.txt  logicmonitor001-memory.txt         company-cassandra003-memory.txt  company-division-rcsgw001-memory.txt  company-waepd003-memory.txt
</code>```

Each file looks similar to this:

```<code>cat haproxy001-memory.txt
7706172
</code>```

I read each file into the existing dataframe.

```<code>rowcount == 0
text_path = '/home/tdun0002/stash/cloud_scripts/output_files/memory_stats/text/'
filelist = os.listdir(text_path)
for filename in filelist:
    if rowcount == 0:
        pass
    else:
        my_file = text_path + filename
        print(f"Adding {filename} to DF")
        try:
            orig_df = pd.update(my_file)
            print(f"Data Frame: {orif_df}")
            ++rowcount
        except Exception as e:
            print(f"An error has occurred: {e}")
</code>```

But when I try to read the resulting dataframe again it has not been updated. I gave the new DF a new name for clarity.

code:

```<code>result_df = orig_df
pd.options.display.max_rows
print(f"\nResult Data Frame:\n{result_df}\n")
</code>```

output:

```<code>Result Data Frame:
                      Name     PrivateIP
0               bastion001  10.238.2.166
1          logicmonitor001   10.238.2.52
2          logicmonitor002    45.21.2.13
</code>```

How can I create a new column called Memory in the DF and add the contents of the text files to that column?

答:
Here's the code I hope would work. It's a bit clunky, but you'll get the idea. There are comments inside.

```<code>import pandas as pd
import os
from os import listdir
from os.path import isfile, join

# get all files in the directory
# i used os.getcwd() to get the current directory
# if your text files are in another dir, then write exact dir location
# this gets you all files in your text dir
onlyfiles = [f for f in listdir(os.getcwd()) if isfile(join(os.getcwd(), f))]

# convert it to series
memory_series = pd.Series(onlyfiles)

# an apply function to get just txt files
# others will be returned as None
def file_name_getter(x):
    names = x.split(".", maxsplit=1)
    if names[1] == "txt":
        return names[0]
    else:
        return None

# apply the function and get a new series with name values
mem_list = memory_series.apply(lambda x: file_name_getter(x))

# now read first line of txt files
# and this is the function for it
def get_txt_data(x):
    if x != None:
        with open(f'{x}.txt') as f:
            return int(f.readline().rstrip())
    else:
        return 0

# apply the function, get a new series with memory values
mem_val_list = mem_list.apply(lambda x: get_txt_data(x))

# create a df where our Name and Memory data are present
# cast Memory data as int
df = pd.DataFrame(mem_val_list, columns=["Memory"], dtype="int")
df["Name"] = mem_list

# get rid of -memory now
def name_normalizer(x):
    if x is None:
        return x
    else:
        return x.rsplit("-", maxsplit=1)[0]

# apply function
df["Name"] = df["Name"].apply(lambda x:  name_normalizer(x))

# our sample orig_df
orig_df = pd.DataFrame([["algo_2", "10.10.10"], ["other", "20.20.20"]], columns=["Name", "PrivateIP"])

# merge using on, so if we miss data; that data wont cause any problem
# all matching names will get their memory values
final_df = orig_df.merge(df, on="Name")
</code>```

edit: fixed Name to be returned correctly. (xxx-memory to xxx)

Body:
I am reading a CSV file into a pandas dataframe using Python. I want to read in a list of text files into a new column of the dataframe.

The original CSV file I'm reading from looks like this:

Name,PrivateIP
bastion001,10.238.2.166
logicmonitor001,10.238.2.52
logicmonitor002,45.21.2.13

The original dataframe looks like this.

code:

hosts_list = dst = os.path.join('..', '..', 'source_files', 'aws_hosts_list', 'aws_hosts_list.csv')
fields = ["Name", "PrivateIP"]
orig_df = pd.read_csv(hosts_list, skipinitialspace=True, usecols=fields)
print(f"Orig DF: {orig_df}")

output:

Orig DF:
                       Name     PrivateIP
0               bastion001  10.238.2.166
1          logicmonitor001   10.238.2.52
2         logicmonitor002    45.21.2.13

The text directory has a bunch of text files in it with memory readings in each:

bastion001-memory.txt              B-mmp-rabbitmq-core002-memory.txt  logicmonitor002-memory.txt    mmp-cassandra001-memory.txt  company-division-rcsgw002-memory.txt
B-mmp-platsvc-core001-memory.txt   haproxy001-memory.txt              company-cassandra001-memory.txt  mmp-cassandra002-memory.txt  company-waepd001-memory.txt
B-mmp-platsvc-core002-memory.txt   haproxy002-memory.txt              company-cassandra002-memory.txt  mmp-cassandra003-memory.txt  company-waepd002-memory.txt
B-mmp-rabbitmq-core001-memory.txt  logicmonitor001-memory.txt         company-cassandra003-memory.txt  company-division-rcsgw001-memory.txt  company-waepd003-memory.txt

Each file looks similar to this:

cat haproxy001-memory.txt
7706172

I read each file into the existing dataframe.

rowcount == 0
text_path = '/home/tdun0002/stash/cloud_scripts/output_files/memory_stats/text/'
filelist = os.listdir(text_path)
for filename in filelist:
    if rowcount == 0:
        pass
    else:
        my_file = text_path + filename
        print(f"Adding {filename} to DF")
        try:
            orig_df = pd.update(my_file)
            print(f"Data Frame: {orif_df}")
            ++rowcount
        except Exception as e:
            print(f"An error has occurred: {e}")

But when I try to read the resulting dataframe again it has not been updated. I gave the new DF a new name for clarity.

code:

result_df = orig_df
pd.options.display.max_rows
print(f"\nResult Data Frame:\n{result_df}\n")

output:

Result Data Frame:
                      Name     PrivateIP
0               bastion001  10.238.2.166
1          logicmonitor001   10.238.2.52
2          logicmonitor002    45.21.2.13

How can I create a new column called Memory in the DF and add the contents of the text files to that column?

Body:
Here's the code I hope would work. It's a bit clunky, but you'll get the idea. There are comments inside.

import pandas as pd
import os
from os import listdir
from os.path import isfile, join

# get all files in the directory
# i used os.getcwd() to get the current directory
# if your text files are in another dir, then write exact dir location
# this gets you all files in your text dir
onlyfiles = [f for f in listdir(os.getcwd()) if isfile(join(os.getcwd(), f))]

# convert it to series
memory_series = pd.Series(onlyfiles)

# an apply function to get just txt files
# others will be returned as None
def file_name_getter(x):
    names = x.split(".", maxsplit=1)
    if names[1] == "txt":
        return names[0]
    else:
        return None

# apply the function and get a new series with name values
mem_list = memory_series.apply(lambda x: file_name_getter(x))

# now read first line of txt files
# and this is the function for it
def get_txt_data(x):
    if x != None:
        with open(f'{x}.txt') as f:
            return int(f.readline().rstrip())
    else:
        return 0

# apply the function, get a new series with memory values
mem_val_list = mem_list.apply(lambda x: get_txt_data(x))

# create a df where our Name and Memory data are present
# cast Memory data as int
df = pd.DataFrame(mem_val_list, columns=["Memory"], dtype="int")
df["Name"] = mem_list

# get rid of -memory now
def name_normalizer(x):
    if x is None:
        return x
    else:
        return x.rsplit("-", maxsplit=1)[0]

# apply function
df["Name"] = df["Name"].apply(lambda x:  name_normalizer(x))

# our sample orig_df
orig_df = pd.DataFrame([["algo_2", "10.10.10"], ["other", "20.20.20"]], columns=["Name", "PrivateIP"])

# merge using on, so if we miss data; that data wont cause any problem
# all matching names will get their memory values
final_df = orig_df.merge(df, on="Name")

edit: fixed Name to be returned correctly. (xxx-memory to xxx)


问:
Schema Compare and SqlPackage 150 case sensitivity issues
So I installed the new SqlPackage 150 (having had 140 before with no issues) and deploying the database twice (sqlpackage is a joke, this twice needs to be done on any update to see what new quirks it has when it alters untouched code), I noticed it's altering functions even if no changes occurred in actual code. Having had trouble before with SqlPackage and it's very poorly designed comparison methods, I learned to workaround them:

don't use iif, use case

keep entire case when then ... end on a single line no matter how long it is

always wrap in parenthesis (default values) and (computed fields)

name all constraints (pks, uniques, checks)

Today, something new came up. All my sql code is written in lower-case and all names are quoted [name], so it is clean like: create function [dbo].[fnFunction1](...). But new SqlPackage decided to alter ALL my functions. Not procedures, not tables, not views, not triggers even if all are written in lower-case create *. I tried to publish 3 times, same thing. Only functions are altered, always.

So I ran Schema Compare to see what is the problem. That's how I previously found the quirks of sqlpackage I listed before, through trial and error. I looked at the differences and always there is a single difference:

local code has create function ...

remote code has CREATE function ...

Yes, I do have Ignore keyword casing checked in Schema Compare options and in the Publish Profile in the SSDT Project. It seems to be irrelevant in functions.

The difference in casing causes the functions to be altered but nothing else even if I always use (and have always used) create in lower-case. So remotely it wants CREATE function while locally it has create function. While create table\view\procedure\trigger\index\... is cool.

What is happening here? I really don't want to change the functions casing, also I don't want to alter on every publish, also don't want to revert to SqlPackage 140.

Issue did not happen using SqlPackage140 with SqlServer 2019 but occurs on SqlPackage150 with SqlServer 2019.

答:
This behavior has been fixed with the latest SQLpackage. But it did not update itself, I had to do it myself manually.

[EDIT] Wrote a PowerShell script to auto-update so I can run it every now and then and it does the work for me. (I'm new to PS so... it might be bad, but it works.)