问:
Pyspark + Redis Remote Server
I have a server with redis and maven configured
I then do the following sparkSession

```<code>spark = pyspark
.sql
.SparkSession
.builder
.master('local[4]')
.appName('try_one_core')
.config("spark.redis.host", "XX.XXX.XXX.XXX")
.config("spark.redis.port", "6379")
.config("spark.redis.auth", "XXXX")
.getOrCreate()
</code>```

I am trying to connect to a remote redis server and write/load data from it, however when I try to .save() with the following command

```<code>df
.write
.format("org.apache.spark.sql.redis")
.option("table", "df")
.option("key.column", "case_id")
.save()
</code>```

I get the following error:

py4j.protocol.Py4JJavaError: An error occurred while calling
  o327.save. : java.lang.ClassNotFoundException: Failed to find data
  source: org.apache.spark.sql.redis. Please find packages at
  http://spark.apache.org/third-party-projects.html

Is there any fix to this?

答:
It means that spark-redis-<version>-jar-with-dependencies.jar is not loaded in Spark.

You have to run pyspark with the following arguments as stated in the documentation:

$ bin/pyspark --jars <path-to>/spark-redis-<version>-jar-with-dependencies.jar --conf "spark.redis.host=localhost" --conf "spark.redis.port=6379" --conf "spark.redis.auth=passwd"

Title: Pyspark + Redis Remote Server

Body:
I have a server with redis and maven configured
I then do the following sparkSession

spark = pyspark
.sql
.SparkSession
.builder
.master('local[4]')
.appName('try_one_core')
.config("spark.redis.host", "XX.XXX.XXX.XXX")
.config("spark.redis.port", "6379")
.config("spark.redis.auth", "XXXX")
.getOrCreate()

I am trying to connect to a remote redis server and write/load data from it, however when I try to .save() with the following command

df
.write
.format("org.apache.spark.sql.redis")
.option("table", "df")
.option("key.column", "case_id")
.save()

I get the following error:

py4j.protocol.Py4JJavaError: An error occurred while calling
  o327.save. : java.lang.ClassNotFoundException: Failed to find data
  source: org.apache.spark.sql.redis. Please find packages at
  http://spark.apache.org/third-party-projects.html

Is there any fix to this?


来源: stackexchange

问:
Searching a field inside a leaf in a mongo collection with regex
I have the following mongo collection with records as seen in the json example record below which represents one record. My goal is for example to search for the word "CONST" and find records where the "FullName" field inside the "Aliases" subtree contains this word. Taking the record shown as example, it should hit because the leaves 533-1 and 533-2 inside the "Aliases" tree contain the string "CONST" on their respective "FullName" fields. If the Aliases tree contained only the 533-3 leaf inside tree for example, it wouldn't hit.

I use C# and the MongoDb.Driver package and to search with Regex for normal fields - e.g. for "Key" on this collection shown I use "Builders.Filter.And(filter, Builders.Filter.Regex("Key", new BsonRegularExpression("")))" pattern to add a condition. But for these fields inside the "Aliases" subtree I don't know how to add a condition. What would be the simplest way to make a search on this field?

Please note that under "Aliases" each leaf has a different name (533-1, 533-2 etc). Each name of each leaf is unique in every record in the entire collection.
Record example:

```<code>{
"_id" : "128c5c57-ae95-4a08-9fb8-d6eade663908",
"_t" : "Company",
"ActiveFrom" : "20190813154343",
"ActiveTo" : "30001001000001",
"GroupId" : "38547478-88ef-4caf-a6ce-1a9e6a85a59b",
"Key" : "533",
"FullName" : "RED BRIGADES",
"Countries" : [
    "ITALY"
],
"MoreInfo" : null,
"RecordDetail" : "<RecordDetail></RecordDetail>",
"Aliases" : {
    "533-1" : {
        "Key" : "533-1",
        "FullName" : "BRIGADAS ROJAS PARA LA CONSTRUCCIÓN DEL PARTIDO COMUNISTA COMBATIENTE",
        "OriginalKey" : "533"
    },
    "533-2" : {
        "Key" : "533-2",
        "FullName" : "BRIGADES ROUGES POUR LA CONSTRUCTION DU PARTI COMMUNISTE COMBATTANT",
        "OriginalKey" : "533"
    },
    "533-3" : {
        "Key" : "533-3",
        "FullName" : "BRIGATE ROSSE",
        "OriginalKey" : "533"
    },
    "533-4" : {
        "Key" : "533-4",
        "FullName" : "BRIGATE ROSSE PER LA COSTRUZIONE DEL PARTITO COMUNISTA COMBATTENTE",
        "OriginalKey" : "533"
    }
}
</code>```

}

答:
the following aggregation pipeline will get you the results you want. i don't think it would be worth it to try to build this pipeline in c# as there's no builder for objectToArray which is needed in your case. if your alias leafs were array items, then we could build a pipeline using the driver's builders. maybe someone else has a better approach. let's see...

db.companies.aggregate([
{
  $match: {
    $expr: {
      $gt: [
        {
          $size: {
            $filter: {
              input: {
                $objectToArray: "$Aliases"
              },
              as: "alias",
              cond: {
                $regexMatch: {
                  input: "$$alias.v.FullName",
                  regex: /CONST/
                }
              }
            }
          }
        },
        0
      ]
    }
  }
}
])
```

ContentLicense: CC BY-SA 4.0

Body:
I have the following mongo collection with records as seen in the json example record below which represents one record. My goal is for example to search for the word "CONST" and find records where the "FullName" field inside the "Aliases" subtree contains this word. Taking the record shown as example, it should hit because the leaves 533-1 and 533-2 inside the "Aliases" tree contain the string "CONST" on their respective "FullName" fields. If the Aliases tree contained only the 533-3 leaf inside tree for example, it wouldn't hit.

I use C# and the MongoDb.Driver package and to search with Regex for normal fields - e.g. for "Key" on this collection shown I use "Builders.Filter.And(filter, Builders.Filter.Regex("Key", new BsonRegularExpression("")))" pattern to add a condition. But for these fields inside the "Aliases" subtree I don't know how to add a condition. What would be the simplest way to make a search on this field?

Please note that under "Aliases" each leaf has a different name (533-1, 533-2 etc). Each name of each leaf is unique in every record in the entire collection.
Record example:

{
"_id" : "128c5c57-ae95-4a08-9fb8-d6eade663908",
"_t" : "Company",
"ActiveFrom" : "20190813154343",
"ActiveTo" : "30001001000001",
"GroupId" : "38547478-88ef-4caf-a6ce-1a9e6a85a59b",
"Key" : "533",
"FullName" : "RED BRIGADES",
"Countries" : [
    "ITALY"
],
"MoreInfo" : null,
"RecordDetail" : "<RecordDetail></RecordDetail>",
"Aliases" : {
    "533-1" : {
        "Key" : "533-1",
        "FullName" : "BRIGADAS ROJAS PARA LA CONSTRUCCIÓN DEL PARTIDO COMUNISTA COMBATIENTE",
        "OriginalKey" : "533"
    },
    "533-2" : {
        "Key" : "533-2",
        "FullName" : "BRIGADES ROUGES POUR LA CONSTRUCTION DU PARTI COMMUNISTE COMBATTANT",
        "OriginalKey" : "533"
    },
    "533-3" : {
        "Key" : "533-3",
        "FullName" : "BRIGATE ROSSE",
        "OriginalKey" : "533"
    },
    "533-4" : {
        "Key" : "533-4",
        "FullName" : "BRIGATE ROSSE PER LA COSTRUZIONE DEL PARTITO COMUNISTA COMBATTENTE",
        "OriginalKey" : "533"
    }
}

}


问:
how use npm packages with Vue SPA
i have created Vuejs app using vue-loader,now i need to use an installed npm package as follow :

   var x = require('package-name')
   Vue.use(x)```
</div>
</div>
</p>

<p>but i have this error :</p>

```Uncaught TypeError: plugin.apply is not a function
```

dose Vuejs require a special type packages or it can work with any JavaScript package and this error can be solved

答:
There is better solution ... First import your package in main.js

import Vue from "vue";
import App from "./App.vue";
import "package-name";```
</div>
</div>
</p>

<p>After that's you code inside mounted method as javascript</p>

<p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
<div class="snippet-code">
<pre class="snippet-code-js lang-js prettyprint-override"><code><script>
export default {
   mounted() {
      const any = require("package-name");
      // your code as normal js
   },
};
</script></code>```

ContentLicense: CC BY-SA 3.0

Title: how use npm packages with Vue SPA

Body:
i have created Vuejs app using vue-loader,now i need to use an installed npm package as follow :

   var x = require('package-name')
   Vue.use(x)

but i have this error :

Uncaught TypeError: plugin.apply is not a function

dose Vuejs require a special type packages or it can work with any JavaScript package and this error can be solved

Body:
There is better solution ... First import your package in main.js

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
import Vue from "vue";
import App from "./App.vue";
import "package-name";

After that's you code inside mounted method as javascript

<script>
export default {
   mounted() {
      const any = require("package-name");
      // your code as normal js
   },
};
</script>


问:
Why can I not unpack two lists into a format string within a for loop?
I was trying to do a basic spinning animation using "\|/-" which went fine, but I wanted two on the same updating line. With one spinning clockwise and one spinning anti-clockwise.

Here is what I came up with:

```<code>animation_1 = ['\\', '|', '/', '-']
animation_2 = ['/', '|', '\\', '-']

while True:
    for iteration_1, iteration_2 in animation_1, animation_2:
        print(f'\r    {iteration_2}  {iteration_1}', end='')
        sleep(.5)
        sys.stdout.flush()
</code>```

Which get the output:

"Traceback (most recent call last):
  File "/Users/pungkrock/PycharmProjects/ans/fib.py", line 18, in <module>
    for iteration_1, iteration_2 in animation_1, animation_2:
ValueError: too many values to unpack (expected 2)"
```

<p>This example:</p>

```animation_1 = ['\\', '|', '/', '-']
animation_2 = ['/', '|', '\\', '-']

while True:
    for iteration_1, iteration_2 in animation_1:
        print(f'\r    {iteration_2}  {iteration_1}', end='')
        sleep(.5)
        sys.stdout.flush()
```

<p>Gets the output:</p>

<pre class="lang-none prettyprint-override"><code>"Traceback (most recent call last):
  File "/Users/pungkrock/PycharmProjects/ans/fib.py", line 18, in <module>
    for iteration_1, iteration_2 in animation_1:
ValueError: not enough values to unpack (expected 2, got 1)"
</code>```

And this error massage I do understand. But I don't understand why I get an error message from the first example.

This example works fine:

```<code>animation_1 = ['\\', '|', '/', '-']
# animation_2 = ['/', '|', '\\', '-']

while True:
    for iteration_1 in animation_1:
        print(f'\r      {iteration_1}', end='')
        sleep(.5)
        sys.stdout.flush()
</code>```

Can some kind soul explain to me way the first code example doesn't work? Or if I'm missing some basic understanding of some concept of the language?
"too many values to unpack (expected 2)", it did get 2? What am I missing?

答:
```<code>>>> for x in range(4):
...   print(animation_1[x],animation_1[3-x])
...
\ -
| /
/ |
- \
</code>```

<p>sorry, no explanation, i am new to python meself too.... </p>

Body:
I was trying to do a basic spinning animation using "\|/-" which went fine, but I wanted two on the same updating line. With one spinning clockwise and one spinning anti-clockwise.

Here is what I came up with:

animation_1 = ['\\', '|', '/', '-']
animation_2 = ['/', '|', '\\', '-']

while True:
    for iteration_1, iteration_2 in animation_1, animation_2:
        print(f'\r    {iteration_2}  {iteration_1}', end='')
        sleep(.5)
        sys.stdout.flush()

Which get the output:

"Traceback (most recent call last):
  File "/Users/pungkrock/PycharmProjects/ans/fib.py", line 18, in <module>
    for iteration_1, iteration_2 in animation_1, animation_2:
ValueError: too many values to unpack (expected 2)"

This example:

animation_1 = ['\\', '|', '/', '-']
animation_2 = ['/', '|', '\\', '-']

while True:
    for iteration_1, iteration_2 in animation_1:
        print(f'\r    {iteration_2}  {iteration_1}', end='')
        sleep(.5)
        sys.stdout.flush()

Gets the output:

"Traceback (most recent call last):
  File "/Users/pungkrock/PycharmProjects/ans/fib.py", line 18, in <module>
    for iteration_1, iteration_2 in animation_1:
ValueError: not enough values to unpack (expected 2, got 1)"

And this error massage I do understand. But I don't understand why I get an error message from the first example.

This example works fine:

animation_1 = ['\\', '|', '/', '-']
# animation_2 = ['/', '|', '\\', '-']

while True:
    for iteration_1 in animation_1:
        print(f'\r      {iteration_1}', end='')
        sleep(.5)
        sys.stdout.flush()

Can some kind soul explain to me way the first code example doesn't work? Or if I'm missing some basic understanding of some concept of the language?
"too many values to unpack (expected 2)", it did get 2? What am I missing?

Body:
>>> for x in range(4):
...   print(animation_1[x],animation_1[3-x])
...
\ -
| /
/ |
- \

sorry, no explanation, i am new to python meself too....


问:
PARTITION BY row value
I need to partition my output table when a certain row is of a certain value. I have:

```<code>ID|Value|User
-------------
1 |A    |Rick
2 |A    |Rick
3 |B    |Rick
7 |A    |Rick
8 |C    |Rick
4 |A    |Joe
5 |B    |Joe
6 |B    |Joe
</code>```

I need to partition my table for each individual user, and when the value = A, so what I need is:

```<code>Row|ID|Value|User
------------------
1  |1 |A    |Rick
1  |2 |A    |Rick
2  |3 |B    |Rick
1  |7 |A    |Rick
2  |8 |C    |Rick
1  |4 |A    |Joe
2  |5 |B    |Joe
3  |6 |B    |Joe
</code>```

Every value has its own ID.

I've tried things like:

```<code>SELECT ROW_NUMBER() OVER(PARTITION BY User, Value = A ORDER BY ID ASC) AS Row, Value, User FROM...
SELECT ROW_NUMBER() OVER(PARTITION BY User, WHERE Value = A ORDER BY ID ASC) AS Row, Value, User FROM...
etc
</code>```

But I can't seem to figure out how to write it correctly, if it even is possible.

答:
I don't think DENSE_RANK() will work as in your example B would have the same value

```<code>2  |B    |Joe
2  |B    |Joe
</code>```

instead of

```<code>2  |B    |Joe
3  |B    |Joe
</code>```

The best way I've come up with is a two pass method

Use normal ROW_NUMBER() -> ROW_NUMBER() OVER (PARTITION BY c.name ORDER BY c.value) AS rn

Then Use DENSE_RANK() -> DENSE_RANK() OVER (PARTITION BY c.name ORDER BY IIF(c.value = 'a', NULL, c.rn))

The trick here is the ORDER BY where we NULL it based on a condition IIF(c.value = 'a', NULL, c.rn))

```<code>WITH
    cte_dataset ([value], [name])
  AS (SELECT 'A' AS v, 'Rick' AS n
      UNION ALL
      SELECT 'A' AS v, 'Rick' AS n
      UNION ALL
      SELECT 'B' AS v, 'Rick' AS n
      UNION ALL
      SELECT 'C' AS v, 'Rick' AS n
      UNION ALL
      SELECT 'A' AS v, 'Joe' AS n
      UNION ALL
      SELECT 'B' AS v, 'Joe' AS n
      UNION ALL
      SELECT 'B' AS v, 'Joe' AS n)
   , cte_add_simple_order
  AS (
    SELECT
        c.value,
        c.name,
        ROW_NUMBER() OVER (PARTITION BY c.name ORDER BY c.value) AS rn
    FROM cte_dataset c
    )
SELECT
    c.value
  , c.name
  , DENSE_RANK() OVER (PARTITION BY c.name ORDER BY IIF(c.value = 'a', NULL, c.rn))
FROM cte_add_simple_order c
ORDER BY
    c.name DESC
  , c.value ;
</code>```

```<code>|value|name|Rank|
|A    |Rick|1   |
|A    |Rick|1   |
|B    |Rick|2   |
|C    |Rick|3   |
|A    |Joe |1   |
|B    |Joe |2   |
|B    |Joe |3   |
</code>```

Title: PARTITION BY row value

Body:
I need to partition my output table when a certain row is of a certain value. I have:

ID|Value|User
-------------
1 |A    |Rick
2 |A    |Rick
3 |B    |Rick
7 |A    |Rick
8 |C    |Rick
4 |A    |Joe
5 |B    |Joe
6 |B    |Joe

I need to partition my table for each individual user, and when the value = A, so what I need is:

Row|ID|Value|User
------------------
1  |1 |A    |Rick
1  |2 |A    |Rick
2  |3 |B    |Rick
1  |7 |A    |Rick
2  |8 |C    |Rick
1  |4 |A    |Joe
2  |5 |B    |Joe
3  |6 |B    |Joe

Every value has its own ID.

I've tried things like:

SELECT ROW_NUMBER() OVER(PARTITION BY User, Value = A ORDER BY ID ASC) AS Row, Value, User FROM...
SELECT ROW_NUMBER() OVER(PARTITION BY User, WHERE Value = A ORDER BY ID ASC) AS Row, Value, User FROM...
etc

But I can't seem to figure out how to write it correctly, if it even is possible.

Body:
I don't think DENSE_RANK() will work as in your example B would have the same value

2  |B    |Joe
2  |B    |Joe

instead of

2  |B    |Joe
3  |B    |Joe

The best way I've come up with is a two pass method

Use normal ROW_NUMBER() -> ROW_NUMBER() OVER (PARTITION BY c.name ORDER BY c.value) AS rn

Then Use DENSE_RANK() -> DENSE_RANK() OVER (PARTITION BY c.name ORDER BY IIF(c.value = 'a', NULL, c.rn))

The trick here is the ORDER BY where we NULL it based on a condition IIF(c.value = 'a', NULL, c.rn))

WITH
    cte_dataset ([value], [name])
  AS (SELECT 'A' AS v, 'Rick' AS n
      UNION ALL
      SELECT 'A' AS v, 'Rick' AS n
      UNION ALL
      SELECT 'B' AS v, 'Rick' AS n
      UNION ALL
      SELECT 'C' AS v, 'Rick' AS n
      UNION ALL
      SELECT 'A' AS v, 'Joe' AS n
      UNION ALL
      SELECT 'B' AS v, 'Joe' AS n
      UNION ALL
      SELECT 'B' AS v, 'Joe' AS n)
   , cte_add_simple_order
  AS (
    SELECT
        c.value,
        c.name,
        ROW_NUMBER() OVER (PARTITION BY c.name ORDER BY c.value) AS rn
    FROM cte_dataset c
    )
SELECT
    c.value
  , c.name
  , DENSE_RANK() OVER (PARTITION BY c.name ORDER BY IIF(c.value = 'a', NULL, c.rn))
FROM cte_add_simple_order c
ORDER BY
    c.name DESC
  , c.value ;

|value|name|Rank|
|A    |Rick|1   |
|A    |Rick|1   |
|B    |Rick|2   |
|C    |Rick|3   |
|A    |Joe |1   |
|B    |Joe |2   |
|B    |Joe |3   |


问:
Create a Connected Graph With Two Types Of Edges
I want to build a graph that is connected and can only have horizontal or vertical edges. Edges are tracks/track switches.

There are two types of tracks: NormalTrack and TrackSwitch.

NormalTrack: startPoint, endPoint.

TrackSwitch: startPoint, endPoint, secondEndPoint.

The first endPoint is the standard setting which is passable (there is a set switch command which can change the switch setting).

All tracks (switch is also a track) have a unique identifier starting at 1.

With the exception of the first track, a start or end point must always be connected to a start or end point of an existing track. Only one other track (normal track or track switch) can be connected to a point on a track.

Here is an example and how the graph would look like:

```<code>add track (1,1) -> (5,1)
ID -> 1
add switch (5,1) -> (8,1),(5,3)
ID -> 2
add track (1,1) -> (1,-3)
ID -> 3
add track (1,-3) -> (10,-3)
ID -> 4
add track (8,1) -> (10,1)
ID -> 5
add track (10,1) -> (10,-3)
ID -> 6
add track (5,3) -> (8,3)
ID -> 7
</code>```

I have a class Point which represents a Cartesian Point and a class RailNetwork where I am going to implement the graph.
In my Register class I have a Map<Integer, Track> tracks; in which I save all tracks. In this class I also instantiated RailNetwork network = new RailNetwork();

I've already implemented the command interface. Now, I want to create the rail network.

Could someone show me how to implement this way?

EDIT

Here is my current implementation:

```<code>public class RailNetwork {
    private Map<Point, List<Point>> edges = new HashMap<>();

    // Add edge (two points)
    public void addEdge(Point firstCoordinate, Point secondCoordinate) {
        edges.computeIfAbsent(firstCoordinate, x -> new ArrayList<>()).add(secondCoordinate);
        edges.computeIfAbsent(secondCoordinate, x -> new ArrayList<>()).add(firstCoordinate);
    }

    // Return all edges
    public List<Point> getEdges(Point node) {
        return Collections.unmodifiableList(edges.get(node));
    }

    // Check if a set of edges is still connected after removing them
    public boolean isConnectedAfterRemoving(Set<Edge> toRemove) {
        Set<Point> notVisited = edges.entrySet()
                .stream()
                .filter(e -> e.getValue().stream().anyMatch(d -> !toRemove.contains(new Edge(e, d)) &&
                        !toRemove.contains(new Edge(d, e))))
                .map(Map.Entry::getKey).collect(java.util.stream.Collectors.toSet());
        if (notVisited.isEmpty())
            return true;
        visit(notVisited.iterator().next(), notVisited, toRemove);
        return notVisited.isEmpty();
    }

    private void visit(Point next, Set<Point> notVisited, Set<Edge> toRemove) {
        if (!notVisited.remove(next))
            return;
        for (Point point : edges.get(next))
            if (!toRemove.contains(new Edge(next, point)) &&
                    !toRemove.contains(new Edge(point, next)))
                visit(point, notVisited, toRemove);
    }

    private void visitAndRemove(Set<Point> nodes, Point node) {
        if (nodes.contains(node)) {
            nodes.remove(node);
            List<Point> nextNodes = getEdges(node);
            for (Point next : nextNodes) {
                visitAndRemove(nodes, next);
            }
        }
    }
}

public class Edge {
    private final Point source;
    private final Point dest;

    public Edge(Point source, Point dest) {
        this.source = source;
        this.dest = dest;
    }

    @Override
    public boolean equals(Object o) {
        if (o == this || !(o instanceof Edge)) {
            return o == this;
        }

        Edge edge = (Edge) o;
        return Objects.equals(source, edge.source) &&
                Objects.equals(dest, edge.dest);
    }

    @Override
    public int hashCode() {
        return Objects.hash(source, dest);
    }
}
</code>```

I am not sure why my isConnectedAfterRemoving() method doesn't work. How can I fix this?

I also have a abstract class Track and two subclasses NormalTrack and TrackSwitch.

TrackSwitch(int id, Point startPoint, Point endPoint, Point secondEndPoint, int length, boolean switchEnabled)

NormalTrack(int id, Point startPoint, Point endPoint, int length)

How do I continue now..?

答:
You can create two classes NormalTrack and TrackSwitch and represent each track by an instance of that class. The classes store the id, the starting point and the end point(s) of the track.

Then you probably want to store for each point the list of incoming tracks as well as the list of outgoing tracks. A switch is a bit complicated in this setup since it has two endpoints. You probably also need a flag in the switch that tells which endpoint is currently active. Then, when you iterate over the incoming/outgoing tracks of a point and hit a TrackSwitch then you must first check if the point you are iterating is currently active. If not, you have to skip that.

Body:
I want to build a graph that is connected and can only have horizontal or vertical edges. Edges are tracks/track switches.

There are two types of tracks: NormalTrack and TrackSwitch.

NormalTrack: startPoint, endPoint.

TrackSwitch: startPoint, endPoint, secondEndPoint.

The first endPoint is the standard setting which is passable (there is a set switch command which can change the switch setting).

All tracks (switch is also a track) have a unique identifier starting at 1.

With the exception of the first track, a start or end point must always be connected to a start or end point of an existing track. Only one other track (normal track or track switch) can be connected to a point on a track.

Here is an example and how the graph would look like:

add track (1,1) -> (5,1)
ID -> 1
add switch (5,1) -> (8,1),(5,3)
ID -> 2
add track (1,1) -> (1,-3)
ID -> 3
add track (1,-3) -> (10,-3)
ID -> 4
add track (8,1) -> (10,1)
ID -> 5
add track (10,1) -> (10,-3)
ID -> 6
add track (5,3) -> (8,3)
ID -> 7

I have a class Point which represents a Cartesian Point and a class RailNetwork where I am going to implement the graph.
In my Register class I have a Map<Integer, Track> tracks; in which I save all tracks. In this class I also instantiated RailNetwork network = new RailNetwork();

I've already implemented the command interface. Now, I want to create the rail network.

Could someone show me how to implement this way?

EDIT

Here is my current implementation:

public class RailNetwork {
    private Map<Point, List<Point>> edges = new HashMap<>();

    // Add edge (two points)
    public void addEdge(Point firstCoordinate, Point secondCoordinate) {
        edges.computeIfAbsent(firstCoordinate, x -> new ArrayList<>()).add(secondCoordinate);
        edges.computeIfAbsent(secondCoordinate, x -> new ArrayList<>()).add(firstCoordinate);
    }

    // Return all edges
    public List<Point> getEdges(Point node) {
        return Collections.unmodifiableList(edges.get(node));
    }

    // Check if a set of edges is still connected after removing them
    public boolean isConnectedAfterRemoving(Set<Edge> toRemove) {
        Set<Point> notVisited = edges.entrySet()
                .stream()
                .filter(e -> e.getValue().stream().anyMatch(d -> !toRemove.contains(new Edge(e, d)) &&
                        !toRemove.contains(new Edge(d, e))))
                .map(Map.Entry::getKey).collect(java.util.stream.Collectors.toSet());
        if (notVisited.isEmpty())
            return true;
        visit(notVisited.iterator().next(), notVisited, toRemove);
        return notVisited.isEmpty();
    }

    private void visit(Point next, Set<Point> notVisited, Set<Edge> toRemove) {
        if (!notVisited.remove(next))
            return;
        for (Point point : edges.get(next))
            if (!toRemove.contains(new Edge(next, point)) &&
                    !toRemove.contains(new Edge(point, next)))
                visit(point, notVisited, toRemove);
    }

    private void visitAndRemove(Set<Point> nodes, Point node) {
        if (nodes.contains(node)) {
            nodes.remove(node);
            List<Point> nextNodes = getEdges(node);
            for (Point next : nextNodes) {
                visitAndRemove(nodes, next);
            }
        }
    }
}

public class Edge {
    private final Point source;
    private final Point dest;

    public Edge(Point source, Point dest) {
        this.source = source;
        this.dest = dest;
    }

    @Override
    public boolean equals(Object o) {
        if (o == this || !(o instanceof Edge)) {
            return o == this;
        }

        Edge edge = (Edge) o;
        return Objects.equals(source, edge.source) &&
                Objects.equals(dest, edge.dest);
    }

    @Override
    public int hashCode() {
        return Objects.hash(source, dest);
    }
}

I am not sure why my isConnectedAfterRemoving() method doesn't work. How can I fix this?

I also have a abstract class Track and two subclasses NormalTrack and TrackSwitch.

TrackSwitch(int id, Point startPoint, Point endPoint, Point secondEndPoint, int length, boolean switchEnabled)

NormalTrack(int id, Point startPoint, Point endPoint, int length)

How do I continue now..?


问:
find, save and remove duplicate values from more then one array
first array

```<code>[0]=> Brian
[1]=> A
[2]=> Leo
[3]=> A
[4]=> Mike
</code>```

second array

```<code>[0]=> 1
[1]=> 2
[2]=> 3
[3]=> 4
[4]=> 5
</code>```

I want to check if in first array there are duplicates, if yes, save only the first occurrence of that value, the other removes, remember those keys, and delete them from the second array too. In the end i want to have

first array

```<code>[0]=> Brian
[1]=> A
[2]=> Leo
[3]=> Mike
</code>```

second array

```<code>[0]=> 1
[1]=> 2
[2]=> 3
[3]=> 5
</code>```

I tried with this but second array does not have duplicates so it won't work for both array:

```<code>array_values(array_unique($array));
</code>```

答:
Please note that array_unique preserves keys so you can easily use it to filter the second array too:

```<code>$firstArray = array_unique($firstArray);
$secondArray = array_intersect_key($secondArray, $firstArray);

var_dump(array_values($firstArray), array_values($secondArray));
</code>```

From the docs of array_unique:

Note that keys are preserved. If multiple elements compare equal under the given sort_flags, then the key and value of the first equal element will be retained.

Body:
first array

[0]=> Brian
[1]=> A
[2]=> Leo
[3]=> A
[4]=> Mike

second array

[0]=> 1
[1]=> 2
[2]=> 3
[3]=> 4
[4]=> 5

I want to check if in first array there are duplicates, if yes, save only the first occurrence of that value, the other removes, remember those keys, and delete them from the second array too. In the end i want to have

first array

[0]=> Brian
[1]=> A
[2]=> Leo
[3]=> Mike

second array

[0]=> 1
[1]=> 2
[2]=> 3
[3]=> 5

I tried with this but second array does not have duplicates so it won't work for both array:

array_values(array_unique($array));

Body:
Please note that array_unique preserves keys so you can easily use it to filter the second array too:

$firstArray = array_unique($firstArray);
$secondArray = array_intersect_key($secondArray, $firstArray);

var_dump(array_values($firstArray), array_values($secondArray));

From the docs of array_unique:

Note that keys are preserved. If multiple elements compare equal under the given sort_flags, then the key and value of the first equal element will be retained.


问:
Is there any way of finding the font & frame size of the UINavigationBar title?
Is there any way of programatically returning the font and size of the navigation controller's title bar (e.g. self.title.frame.size or self.title.font, although I know neither of those works)?

(In case you're wondering the reason, I would like to use an NSString sizeWithFont method to work out how much text can fit in the title before I truncate it. I could do this by physically measuring the font and frame size myself (e.g. I think it's Helvetica 15), but I want the actual title to report its own font and size, to make my app future-proof.)

答:
I've worked out how to get the frame:

self.navigationItem.titleView.frame.size

Which just leaves the font. My research indicates that it's the System Font at size 20, but I'd love it to be self-reporting.

EDIT - well that's odd. If I do ...

```<code> self.title = @"test";
 NSLog(@"Width is: %f", self.navigationItem.titleView.frame.size.width);
</code>```

... I get random negative numbers from the NSLog. So it doesn't look like the title frame is right.

Body:
I've worked out how to get the frame:

self.navigationItem.titleView.frame.size

Which just leaves the font. My research indicates that it's the System Font at size 20, but I'd love it to be self-reporting.

EDIT - well that's odd. If I do ...

 self.title = @"test";
 NSLog(@"Width is: %f", self.navigationItem.titleView.frame.size.width);

... I get random negative numbers from the NSLog. So it doesn't look like the title frame is right.


问:
Drag to dismiss Activity not calling onDrag
I'm trying to create an activity which can be dismissed on drag using the example in Nick Butcher's Plaid app. I have literally used his code as is and the draggableListener does seem to be added, but for some reason, onDrag doesn't seem to be called when I drag on the activity, and therefore the activity doesn't finish.

ElasticDragDismissFrameLayout.java

```<code>package io.traffitool.ui.widget;

import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.FrameLayout;

import java.util.ArrayList;
import java.util.List;

import io.traffitool.R;
import io.traffitool.util.AnimUtils;
import io.traffitool.util.ColorUtils;
import io.traffitool.util.ViewUtils;

public class ElasticDragDismissFrameLayout extends FrameLayout {

    // configurable attribs
    private float dragDismissDistance = Float.MAX_VALUE;
    private float dragDismissFraction = -1f;
    private float dragDismissScale = 1f;
    private boolean shouldScale = false;
    private float dragElacticity = 0.8f;

    // state
    private float totalDrag;
    private boolean draggingDown = false;
    private boolean draggingUp = false;

    private List<ElasticDragDismissCallback> callbacks;

    public ElasticDragDismissFrameLayout(Context context) {
        this(context, null, 0, 0);
    }

    public ElasticDragDismissFrameLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0, 0);
    }

    public ElasticDragDismissFrameLayout(Context context, AttributeSet attrs,
                                         int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public ElasticDragDismissFrameLayout(Context context, AttributeSet attrs,
                                         int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);

        final TypedArray a = getContext().obtainStyledAttributes(
                attrs, R.styleable.ElasticDragDismissFrameLayout, 0, 0);

        if (a.hasValue(R.styleable.ElasticDragDismissFrameLayout_dragDismissDistance)) {
            dragDismissDistance = a.getDimensionPixelSize(R.styleable
                    .ElasticDragDismissFrameLayout_dragDismissDistance, 0);
        } else if (a.hasValue(R.styleable.ElasticDragDismissFrameLayout_dragDismissFraction)) {
            dragDismissFraction = a.getFloat(R.styleable
                    .ElasticDragDismissFrameLayout_dragDismissFraction, dragDismissFraction);
        }
        if (a.hasValue(R.styleable.ElasticDragDismissFrameLayout_dragDismissScale)) {
            dragDismissScale = a.getFloat(R.styleable
                    .ElasticDragDismissFrameLayout_dragDismissScale, dragDismissScale);
            shouldScale = dragDismissScale != 1f;
        }
        if (a.hasValue(R.styleable.ElasticDragDismissFrameLayout_dragElasticity)) {
            dragElacticity = a.getFloat(R.styleable.ElasticDragDismissFrameLayout_dragElasticity,
                    dragElacticity);
        }
        a.recycle();
    }

    public static abstract class ElasticDragDismissCallback {

        /**
         * Called for each drag event.
         *
         * @param elasticOffset       Indicating the drag offset with elasticity applied i.e. may
         *                            exceed 1.
         * @param elasticOffsetPixels The elastically scaled drag distance in pixels.
         * @param rawOffset           Value from [0, 1] indicating the raw drag offset i.e.
         *                            without elasticity applied. A value of 1 indicates that the
         *                            dismiss distance has been reached.
         * @param rawOffsetPixels     The raw distance the user has dragged
         */
        void onDrag(float elasticOffset, float elasticOffsetPixels,
                    float rawOffset, float rawOffsetPixels) {
            Log.d("EDDFL: ", "onDrag");
        }

        /**
         * Called when dragging is released and has exceeded the threshold dismiss distance.
         */
        void onDragDismissed() {
            Log.d("EDDFL: ", "onDragDismissed");
        }

    }

    @Override
    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
        return (nestedScrollAxes & View.SCROLL_AXIS_VERTICAL) != 0;
    }

    @Override
    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
        // if we're in a drag gesture and the user reverses up the we should take those events
        if (draggingDown && dy > 0 || draggingUp && dy < 0) {
            dragScale(dy);
            consumed[1] = dy;
        }
    }

    @Override
    public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
                               int dxUnconsumed, int dyUnconsumed) {
        dragScale(dyUnconsumed);
    }

    @Override
    public void onStopNestedScroll(View child) {
        if (Math.abs(totalDrag) >= dragDismissDistance) {
            dispatchDismissCallback();
        } else { // settle back to natural position
            animate()
                    .translationY(0f)
                    .scaleX(1f)
                    .scaleY(1f)
                    .setDuration(200L)
                    .setInterpolator(AnimUtils.getFastOutSlowInInterpolator(getContext()))
                    .setListener(null)
                    .start();
            totalDrag = 0;
            draggingDown = draggingUp = false;
            dispatchDragCallback(0f, 0f, 0f, 0f);
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (dragDismissFraction > 0f) {
            dragDismissDistance = h * dragDismissFraction;
        }
    }

    public void addListener(ElasticDragDismissCallback listener) {
        if (callbacks == null) {
            callbacks = new ArrayList<>();
        }
        callbacks.add(listener);
    }

    public void removeListener(ElasticDragDismissCallback listener) {
        if (callbacks != null && callbacks.size() > 0) {
            callbacks.remove(listener);
        }
    }

    private void dragScale(int scroll) {
        if (scroll == 0) return;

        totalDrag += scroll;

        // track the direction & set the pivot point for scaling
        // don't double track i.e. if start dragging down and then reverse, keep tracking as
        // dragging down until they reach the 'natural' position
        if (scroll < 0 && !draggingUp && !draggingDown) {
            draggingDown = true;
            if (shouldScale) setPivotY(getHeight());
        } else if (scroll > 0 && !draggingDown && !draggingUp) {
            draggingUp = true;
            if (shouldScale) setPivotY(0f);
        }
        // how far have we dragged relative to the distance to perform a dismiss
        // (0–1 where 1 = dismiss distance). Decreasing logarithmically as we approach the limit
        float dragFraction = (float) Math.log10(1 + (Math.abs(totalDrag) / dragDismissDistance));

        // calculate the desired translation given the drag fraction
        float dragTo = dragFraction * dragDismissDistance * dragElacticity;

        if (draggingUp) {
            // as we use the absolute magnitude when calculating the drag fraction, need to
            // re-apply the drag direction
            dragTo *= -1;
        }
        setTranslationY(dragTo);

        if (shouldScale) {
            final float scale = 1 - ((1 - dragDismissScale) * dragFraction);
            setScaleX(scale);
            setScaleY(scale);
        }

        // if we've reversed direction and gone past the settle point then clear the flags to
        // allow the list to get the scroll events & reset any transforms
        if ((draggingDown && totalDrag >= 0)
                || (draggingUp && totalDrag <= 0)) {
            totalDrag = dragTo = dragFraction = 0;
            draggingDown = draggingUp = false;
            setTranslationY(0f);
            setScaleX(1f);
            setScaleY(1f);
        }
        dispatchDragCallback(dragFraction, dragTo,
                Math.min(1f, Math.abs(totalDrag) / dragDismissDistance), totalDrag);
    }

    private void dispatchDragCallback(float elasticOffset, float elasticOffsetPixels,
                                      float rawOffset, float rawOffsetPixels) {
        if (callbacks != null && !callbacks.isEmpty()) {
            for (ElasticDragDismissCallback callback : callbacks) {
                callback.onDrag(elasticOffset, elasticOffsetPixels,
                        rawOffset, rawOffsetPixels);
            }
        }
    }

    private void dispatchDismissCallback() {
        if (callbacks != null && !callbacks.isEmpty()) {
            for (ElasticDragDismissCallback callback : callbacks) {
                callback.onDragDismissed();
            }
        }
    }

    /**
     * An {@link ElasticDragDismissCallback} which fades system chrome (i.e. status bar and
     * navigation bar) whilst elastic drags are performed and
     * {@link Activity#finishAfterTransition() finishes} the activity when drag dismissed.
     */
    public static class SystemChromeFader extends ElasticDragDismissCallback {

        private final Activity activity;
        private final int statusBarAlpha;
        private final int navBarAlpha;
        private final boolean fadeNavBar;

        public SystemChromeFader(Activity activity) {
            this.activity = activity;
            statusBarAlpha = Color.alpha(activity.getWindow().getStatusBarColor());
            navBarAlpha = Color.alpha(activity.getWindow().getNavigationBarColor());
            fadeNavBar = ViewUtils.isNavBarOnBottom(activity);
        }

        @Override
        public void onDrag(float elasticOffset, float elasticOffsetPixels,
                           float rawOffset, float rawOffsetPixels) {
            if (elasticOffsetPixels > 0) {
                // dragging downward, fade the status bar in proportion
                activity.getWindow().setStatusBarColor(ColorUtils.modifyAlpha(activity.getWindow()
                        .getStatusBarColor(), (int) ((1f - rawOffset) * statusBarAlpha)));
            } else if (elasticOffsetPixels == 0) {
                // reset
                activity.getWindow().setStatusBarColor(ColorUtils.modifyAlpha(
                        activity.getWindow().getStatusBarColor(), statusBarAlpha));
                activity.getWindow().setNavigationBarColor(ColorUtils.modifyAlpha(
                        activity.getWindow().getNavigationBarColor(), navBarAlpha));
            } else if (fadeNavBar) {
                // dragging upward, fade the navigation bar in proportion
                activity.getWindow().setNavigationBarColor(
                        ColorUtils.modifyAlpha(activity.getWindow().getNavigationBarColor(),
                                (int) ((1f - rawOffset) * navBarAlpha)));
            }
        }

        public void onDragDismissed() {
            activity.finishAfterTransition();
        }
    }

}
</code>```

ProjectActivity.java

```<code>package io.traffitool.ui;

import android.app.Activity;
import android.os.Bundle;
import android.support.v7.widget.RecyclerView;
import android.util.Log;

import butterknife.BindView;
import butterknife.ButterKnife;
import io.traffitool.R;
import io.traffitool.ui.widget.ElasticDragDismissFrameLayout;

public class ProjectActivity extends Activity {

    private static final String TAG = "ProjectActivity: ";

    @BindView(R.id.draggable_frame) ElasticDragDismissFrameLayout draggableFrame;
    @BindView(R.id.list)RecyclerView list;

    private ElasticDragDismissFrameLayout.SystemChromeFader chromeFader;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_project);
        ButterKnife.bind(this);

        chromeFader = new ElasticDragDismissFrameLayout.SystemChromeFader(this) {
            @Override
            public void onDragDismissed() {
                Log.d(TAG, "onDragDismissed");
                setResultandFinish();
            }
        };

        draggableFrame.addListener(chromeFader);
        Log.d(TAG, "draggableListenerAdded");

    }

    void setResultandFinish() {
        Log.d(TAG, "setResultandFinish");
        finish();
    }

}
</code>```

activity_project.xml

```<code><?xml version="1.0" encoding="utf-8"?>

<io.traffitool.ui.widget.ElasticDragDismissFrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/draggable_frame"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:transitionGroup="false"
    app:dragDismissDistance="@dimen/drag_dismiss_distance"
    app:dragDismissScale="0.95"
    tools:context=".ui.ProjectActivity">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:clipToPadding="false"
            android:orientation="vertical"
            android:paddingBottom="@dimen/padding_normal"
            android:scrollbarStyle="insideOverlay"
            android:scrollbars="vertical"
            app:layoutManager="android.support.v7.widget.LinearLayoutManager" />

</io.traffitool.ui.widget.ElasticDragDismissFrameLayout>
</code>```

答:
I ran into a similar issue with ViewPager2 and upon having a deeper look at Plaid, I noticed that each item's layout in the RecyclerView.Adapter had a ScrollView with android:nestedScrollingEnabled="true", e.g. about_icon.xml.

Wrapping each layout in a NestedScrollView enabled nested scroll events in ElasticDragDismissFrameLayout for me.

recycler_item.xml

<androidx.core.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true">

</androidx.core.widget.NestedScrollView>
```

Body:
I'm trying to create an activity which can be dismissed on drag using the example in Nick Butcher's Plaid app. I have literally used his code as is and the draggableListener does seem to be added, but for some reason, onDrag doesn't seem to be called when I drag on the activity, and therefore the activity doesn't finish.

ElasticDragDismissFrameLayout.java

package io.traffitool.ui.widget;

import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.FrameLayout;

import java.util.ArrayList;
import java.util.List;

import io.traffitool.R;
import io.traffitool.util.AnimUtils;
import io.traffitool.util.ColorUtils;
import io.traffitool.util.ViewUtils;

public class ElasticDragDismissFrameLayout extends FrameLayout {

    // configurable attribs
    private float dragDismissDistance = Float.MAX_VALUE;
    private float dragDismissFraction = -1f;
    private float dragDismissScale = 1f;
    private boolean shouldScale = false;
    private float dragElacticity = 0.8f;

    // state
    private float totalDrag;
    private boolean draggingDown = false;
    private boolean draggingUp = false;

    private List<ElasticDragDismissCallback> callbacks;

    public ElasticDragDismissFrameLayout(Context context) {
        this(context, null, 0, 0);
    }

    public ElasticDragDismissFrameLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0, 0);
    }

    public ElasticDragDismissFrameLayout(Context context, AttributeSet attrs,
                                         int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public ElasticDragDismissFrameLayout(Context context, AttributeSet attrs,
                                         int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);

        final TypedArray a = getContext().obtainStyledAttributes(
                attrs, R.styleable.ElasticDragDismissFrameLayout, 0, 0);

        if (a.hasValue(R.styleable.ElasticDragDismissFrameLayout_dragDismissDistance)) {
            dragDismissDistance = a.getDimensionPixelSize(R.styleable
                    .ElasticDragDismissFrameLayout_dragDismissDistance, 0);
        } else if (a.hasValue(R.styleable.ElasticDragDismissFrameLayout_dragDismissFraction)) {
            dragDismissFraction = a.getFloat(R.styleable
                    .ElasticDragDismissFrameLayout_dragDismissFraction, dragDismissFraction);
        }
        if (a.hasValue(R.styleable.ElasticDragDismissFrameLayout_dragDismissScale)) {
            dragDismissScale = a.getFloat(R.styleable
                    .ElasticDragDismissFrameLayout_dragDismissScale, dragDismissScale);
            shouldScale = dragDismissScale != 1f;
        }
        if (a.hasValue(R.styleable.ElasticDragDismissFrameLayout_dragElasticity)) {
            dragElacticity = a.getFloat(R.styleable.ElasticDragDismissFrameLayout_dragElasticity,
                    dragElacticity);
        }
        a.recycle();
    }

    public static abstract class ElasticDragDismissCallback {

        /**
         * Called for each drag event.
         *
         * @param elasticOffset       Indicating the drag offset with elasticity applied i.e. may
         *                            exceed 1.
         * @param elasticOffsetPixels The elastically scaled drag distance in pixels.
         * @param rawOffset           Value from [0, 1] indicating the raw drag offset i.e.
         *                            without elasticity applied. A value of 1 indicates that the
         *                            dismiss distance has been reached.
         * @param rawOffsetPixels     The raw distance the user has dragged
         */
        void onDrag(float elasticOffset, float elasticOffsetPixels,
                    float rawOffset, float rawOffsetPixels) {
            Log.d("EDDFL: ", "onDrag");
        }

        /**
         * Called when dragging is released and has exceeded the threshold dismiss distance.
         */
        void onDragDismissed() {
            Log.d("EDDFL: ", "onDragDismissed");
        }

    }

    @Override
    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
        return (nestedScrollAxes & View.SCROLL_AXIS_VERTICAL) != 0;
    }

    @Override
    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
        // if we're in a drag gesture and the user reverses up the we should take those events
        if (draggingDown && dy > 0 || draggingUp && dy < 0) {
            dragScale(dy);
            consumed[1] = dy;
        }
    }

    @Override
    public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
                               int dxUnconsumed, int dyUnconsumed) {
        dragScale(dyUnconsumed);
    }

    @Override
    public void onStopNestedScroll(View child) {
        if (Math.abs(totalDrag) >= dragDismissDistance) {
            dispatchDismissCallback();
        } else { // settle back to natural position
            animate()
                    .translationY(0f)
                    .scaleX(1f)
                    .scaleY(1f)
                    .setDuration(200L)
                    .setInterpolator(AnimUtils.getFastOutSlowInInterpolator(getContext()))
                    .setListener(null)
                    .start();
            totalDrag = 0;
            draggingDown = draggingUp = false;
            dispatchDragCallback(0f, 0f, 0f, 0f);
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (dragDismissFraction > 0f) {
            dragDismissDistance = h * dragDismissFraction;
        }
    }

    public void addListener(ElasticDragDismissCallback listener) {
        if (callbacks == null) {
            callbacks = new ArrayList<>();
        }
        callbacks.add(listener);
    }

    public void removeListener(ElasticDragDismissCallback listener) {
        if (callbacks != null && callbacks.size() > 0) {
            callbacks.remove(listener);
        }
    }

    private void dragScale(int scroll) {
        if (scroll == 0) return;

        totalDrag += scroll;

        // track the direction & set the pivot point for scaling
        // don't double track i.e. if start dragging down and then reverse, keep tracking as
        // dragging down until they reach the 'natural' position
        if (scroll < 0 && !draggingUp && !draggingDown) {
            draggingDown = true;
            if (shouldScale) setPivotY(getHeight());
        } else if (scroll > 0 && !draggingDown && !draggingUp) {
            draggingUp = true;
            if (shouldScale) setPivotY(0f);
        }
        // how far have we dragged relative to the distance to perform a dismiss
        // (0–1 where 1 = dismiss distance). Decreasing logarithmically as we approach the limit
        float dragFraction = (float) Math.log10(1 + (Math.abs(totalDrag) / dragDismissDistance));

        // calculate the desired translation given the drag fraction
        float dragTo = dragFraction * dragDismissDistance * dragElacticity;

        if (draggingUp) {
            // as we use the absolute magnitude when calculating the drag fraction, need to
            // re-apply the drag direction
            dragTo *= -1;
        }
        setTranslationY(dragTo);

        if (shouldScale) {
            final float scale = 1 - ((1 - dragDismissScale) * dragFraction);
            setScaleX(scale);
            setScaleY(scale);
        }

        // if we've reversed direction and gone past the settle point then clear the flags to
        // allow the list to get the scroll events & reset any transforms
        if ((draggingDown && totalDrag >= 0)
                || (draggingUp && totalDrag <= 0)) {
            totalDrag = dragTo = dragFraction = 0;
            draggingDown = draggingUp = false;
            setTranslationY(0f);
            setScaleX(1f);
            setScaleY(1f);
        }
        dispatchDragCallback(dragFraction, dragTo,
                Math.min(1f, Math.abs(totalDrag) / dragDismissDistance), totalDrag);
    }

    private void dispatchDragCallback(float elasticOffset, float elasticOffsetPixels,
                                      float rawOffset, float rawOffsetPixels) {
        if (callbacks != null && !callbacks.isEmpty()) {
            for (ElasticDragDismissCallback callback : callbacks) {
                callback.onDrag(elasticOffset, elasticOffsetPixels,
                        rawOffset, rawOffsetPixels);
            }
        }
    }

    private void dispatchDismissCallback() {
        if (callbacks != null && !callbacks.isEmpty()) {
            for (ElasticDragDismissCallback callback : callbacks) {
                callback.onDragDismissed();
            }
        }
    }

    /**
     * An {@link ElasticDragDismissCallback} which fades system chrome (i.e. status bar and
     * navigation bar) whilst elastic drags are performed and
     * {@link Activity#finishAfterTransition() finishes} the activity when drag dismissed.
     */
    public static class SystemChromeFader extends ElasticDragDismissCallback {

        private final Activity activity;
        private final int statusBarAlpha;
        private final int navBarAlpha;
        private final boolean fadeNavBar;

        public SystemChromeFader(Activity activity) {
            this.activity = activity;
            statusBarAlpha = Color.alpha(activity.getWindow().getStatusBarColor());
            navBarAlpha = Color.alpha(activity.getWindow().getNavigationBarColor());
            fadeNavBar = ViewUtils.isNavBarOnBottom(activity);
        }

        @Override
        public void onDrag(float elasticOffset, float elasticOffsetPixels,
                           float rawOffset, float rawOffsetPixels) {
            if (elasticOffsetPixels > 0) {
                // dragging downward, fade the status bar in proportion
                activity.getWindow().setStatusBarColor(ColorUtils.modifyAlpha(activity.getWindow()
                        .getStatusBarColor(), (int) ((1f - rawOffset) * statusBarAlpha)));
            } else if (elasticOffsetPixels == 0) {
                // reset
                activity.getWindow().setStatusBarColor(ColorUtils.modifyAlpha(
                        activity.getWindow().getStatusBarColor(), statusBarAlpha));
                activity.getWindow().setNavigationBarColor(ColorUtils.modifyAlpha(
                        activity.getWindow().getNavigationBarColor(), navBarAlpha));
            } else if (fadeNavBar) {
                // dragging upward, fade the navigation bar in proportion
                activity.getWindow().setNavigationBarColor(
                        ColorUtils.modifyAlpha(activity.getWindow().getNavigationBarColor(),
                                (int) ((1f - rawOffset) * navBarAlpha)));
            }
        }

        public void onDragDismissed() {
            activity.finishAfterTransition();
        }
    }

}

ProjectActivity.java

package io.traffitool.ui;

import android.app.Activity;
import android.os.Bundle;
import android.support.v7.widget.RecyclerView;
import android.util.Log;

import butterknife.BindView;
import butterknife.ButterKnife;
import io.traffitool.R;
import io.traffitool.ui.widget.ElasticDragDismissFrameLayout;

public class ProjectActivity extends Activity {

    private static final String TAG = "ProjectActivity: ";

    @BindView(R.id.draggable_frame) ElasticDragDismissFrameLayout draggableFrame;
    @BindView(R.id.list)RecyclerView list;

    private ElasticDragDismissFrameLayout.SystemChromeFader chromeFader;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_project);
        ButterKnife.bind(this);

        chromeFader = new ElasticDragDismissFrameLayout.SystemChromeFader(this) {
            @Override
            public void onDragDismissed() {
                Log.d(TAG, "onDragDismissed");
                setResultandFinish();
            }
        };

        draggableFrame.addListener(chromeFader);
        Log.d(TAG, "draggableListenerAdded");

    }

    void setResultandFinish() {
        Log.d(TAG, "setResultandFinish");
        finish();
    }

}

activity_project.xml

<?xml version="1.0" encoding="utf-8"?>

<io.traffitool.ui.widget.ElasticDragDismissFrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/draggable_frame"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:transitionGroup="false"
    app:dragDismissDistance="@dimen/drag_dismiss_distance"
    app:dragDismissScale="0.95"
    tools:context=".ui.ProjectActivity">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:clipToPadding="false"
            android:orientation="vertical"
            android:paddingBottom="@dimen/padding_normal"
            android:scrollbarStyle="insideOverlay"
            android:scrollbars="vertical"
            app:layoutManager="android.support.v7.widget.LinearLayoutManager" />

</io.traffitool.ui.widget.ElasticDragDismissFrameLayout>

Body:
I ran into a similar issue with ViewPager2 and upon having a deeper look at Plaid, I noticed that each item's layout in the RecyclerView.Adapter had a ScrollView with android:nestedScrollingEnabled="true", e.g. about_icon.xml.

Wrapping each layout in a NestedScrollView enabled nested scroll events in ElasticDragDismissFrameLayout for me.

recycler_item.xml

<androidx.core.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true">

    <!-- Content -->

</androidx.core.widget.NestedScrollView>


问:
Dilema: The best way to make table column not sorted
I am creating android app using Kotlin. I have fully functional multi column sorting. When I click on table header column it adds it index to sorting column list. It sorts both ways (ascending and descending). On click it changes direction. Everything works fine. But I would like to know what would be the best solution to remove sorting from one column.

I have few ideas but they don't sound good:

On third column click remove sorting on that column.

Add button which is visible when column is sorted. Button on click removes column from sorted list.

I would like some help because I don't know how to implement this feature in a good way.

Edit1:

Forgot to mention that sorting happens in back-end. In android I just set parameters which columns I need to sort and then send GET request to the server. As response I get sorted data.

答:
I would mimic the way Google Spreadsheets does:

It shows a dialog and you can add sort columns and delete them.

You can see it by selecting some columns and going to Data / Sort the range.

Another possibility would be to have a 3 states switch in each column (sort ascending, sort descending, not sort). Here you can see it working in a website (look at the Multiple column sorting example): http://demos.shieldui.com/web/grid-general/sorting but, in my opinion, it is more confusing.

Hope this helps.


问:
React setState not changing the state
I have an App component that has a state containing a property "faces" , which is initialised after an object

```<code>const initFaces = {
  left : [[0,0,0],[0,0,0],[0,0,0]],
  front : [[1,1,1],[1,1,1],[1,1,1]],
  right : [[2,2,2],[2,2,2],[2,2,2]],
  back : [[3,3,3],[3,3,3],[3,3,3]],
  up : [[4,4,4],[4,4,4],[4,4,4]],
  down : [[5,5,5],[5,5,5],[5,5,5]]
};

class App extends React.component{
 ...
 this.state = {
   faces : initFaces
 }
 ...
}
</code>```

now my app is constantly changing the state of the "faces" property so i tried implementing a button to revert it back to the original state .
This is what i have :

```<code>this.setState({
  faces : initFaces
})
</code>```

But this doesnt work , and this does :

```<code>this.setState({
  faces : {
    left : [[0,0,0],[0,0,0],[0,0,0]],
    front : [[1,1,1],[1,1,1],[1,1,1]],
    right : [[2,2,2],[2,2,2],[2,2,2]],
    back : [[3,3,3],[3,3,3],[3,3,3]],
    up : [[4,4,4],[4,4,4],[4,4,4]],
    down : [[5,5,5],[5,5,5],[5,5,5]]
  }
})
</code>```

Why does it not work simply by referencing the object that has the identical content that i just copied inside of it ?

答:
The issue happens because you are passing the reference to initFaces when initializing your state, so whenever faces changes (assuming you are somehow mutating this.state.faces directly, which is not advised), you are actually changing the same object referenced by initFaces.

You can fix your issue by performing a shallow copy of initFaces when setting the state (and for this, you can use the spread syntax):

```<code>class App extends React.component{
 ...
 this.state = {
   faces : { ...initFaces }
 }
 ...
}
</code>```

And also in your button's implementation to revert the changes:

```<code>this.setState({
  faces : { ...initFaces }
})
</code>```

But if you are indeed directly mutating the state, consider refactoring your code to only change the state by means of setState.

Title: React setState not changing the state

Body:
I have an App component that has a state containing a property "faces" , which is initialised after an object

const initFaces = {
  left : [[0,0,0],[0,0,0],[0,0,0]],
  front : [[1,1,1],[1,1,1],[1,1,1]],
  right : [[2,2,2],[2,2,2],[2,2,2]],
  back : [[3,3,3],[3,3,3],[3,3,3]],
  up : [[4,4,4],[4,4,4],[4,4,4]],
  down : [[5,5,5],[5,5,5],[5,5,5]]
};

class App extends React.component{
 ...
 this.state = {
   faces : initFaces
 }
 ...
}

now my app is constantly changing the state of the "faces" property so i tried implementing a button to revert it back to the original state .
This is what i have :

this.setState({
  faces : initFaces
})

But this doesnt work , and this does :

this.setState({
  faces : {
    left : [[0,0,0],[0,0,0],[0,0,0]],
    front : [[1,1,1],[1,1,1],[1,1,1]],
    right : [[2,2,2],[2,2,2],[2,2,2]],
    back : [[3,3,3],[3,3,3],[3,3,3]],
    up : [[4,4,4],[4,4,4],[4,4,4]],
    down : [[5,5,5],[5,5,5],[5,5,5]]
  }
})

Why does it not work simply by referencing the object that has the identical content that i just copied inside of it ?

Body:
The issue happens because you are passing the reference to initFaces when initializing your state, so whenever faces changes (assuming you are somehow mutating this.state.faces directly, which is not advised), you are actually changing the same object referenced by initFaces.

You can fix your issue by performing a shallow copy of initFaces when setting the state (and for this, you can use the spread syntax):

class App extends React.component{
 ...
 this.state = {
   faces : { ...initFaces }
 }
 ...
}

And also in your button's implementation to revert the changes:

this.setState({
  faces : { ...initFaces }
})

But if you are indeed directly mutating the state, consider refactoring your code to only change the state by means of setState.


问:
Mysql sync on Work and Home computers
I have two Windows 7 systems located in two different locations - work and home, with XAMPP running on both of them. I would like to be able to sync the mysql databases located on the machines. The problem is that both the machines do not stay connnected to the internet continously and do not have dedicated IPs.

I thought of using some cloud hosting service to share the "data" folder in mysql. But for some reason, the tables for the db are not showing up in System #2, thought it said DB(3) - 3 being the number of tables in the database. In this case, i didn't sync the whole of data folder, but the folder of a particular database. Not sure if this is a way of doing it.

Is there a better method of syncing both the databases. Please note that I only work on both the machines and update the database only in one location at a time. So the issue of conflicting records won't occur. I just would like both the systems updated with the same data at the end of the day.

答: Depending on your DB's sizes probably DropBox can be a solution because it mirrors a local directory which may serve as your MySQL data path to their cloud. Although using it for all kinds of snychronisation (including Smalltalk images) I never tried using it as a DB data directory.</p>

Title: Mysql sync on Work and Home computers


问:
Pandas - Add columns based on grouping of other columns
I want to add three additional columns using pandas and python. I'm not sure how to add additional columns based on rows who have the same GroupID value.

min_avg: Which is the lowest avg value for rows with the same GroupID

max_avg: Which is the highest avg value for rows with the same GroupID

group_avg: Which is the avg value for each rows 'min_avg, max_avg' columns

I'm not entirely sure where to begin with this one.

I have this:

```<code>    avg     groupId
0   25.5    1016
1   26.7    1048
2   25.8    1016
3   53.5    1048
4   29.3    1064
5   27.7    1016
</code>```

and my goal is this:

```<code>    avg         groupId     min_avg     max_avg     group_average
0   25.5        1016        25.5        27.7        26.6
1   26.7        1048        26.3        53.5        39.9
2   25.8        1016        25.5        27.7        26.6
3   53.5        1048        26.3        53.5        39.9
4   29.3        1064        29.3        29.3        29.3
5   27.7        1016        25.5        27.7        26.6
</code>```

答:
The describe method, as given in YOBEN_S's solution, will compute more statistics than is required, including count, std, and dtypes. See here.

We can get around this by using the agg method.

```<code>df.merge(df.groupby('groupId')['avg'].agg([min, max, 'mean']), on='groupId')

# output
avg groupId min max mean
0   25.5    1016    25.5    27.7    26.333333
1   26.7    1048    26.7    53.5    40.100000
2   25.8    1016    25.5    27.7    26.333333
3   53.5    1048    26.7    53.5    40.100000
4   29.3    1064    29.3    29.3    29.300000
5   27.7    1016    25.5    27.7    26.333333
</code>```

Speed Comparison

Approach 1

```<code>%%timeit -n 1000

df.merge(df.groupby('groupId').avg.describe()[['mean','min','max']].reset_index(),how='left')
</code>```

9.6 ms ± 123 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Approach 2

```<code>%%timeit -n 1000

df.merge(df.groupby('groupId')['avg'].agg([min, max, 'mean']), on='groupId')
</code>```

3.42 ms ± 74.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Approach 3

Additionally, we can get a slight speedup by converting df.merge to df.join.

2.96 ms ± 29.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Body:
I want to add three additional columns using pandas and python. I'm not sure how to add additional columns based on rows who have the same GroupID value.

min_avg: Which is the lowest avg value for rows with the same GroupID

max_avg: Which is the highest avg value for rows with the same GroupID

group_avg: Which is the avg value for each rows 'min_avg, max_avg' columns

I'm not entirely sure where to begin with this one.

I have this:

    avg     groupId
0   25.5    1016
1   26.7    1048
2   25.8    1016
3   53.5    1048
4   29.3    1064
5   27.7    1016

and my goal is this:

    avg         groupId     min_avg     max_avg     group_average
0   25.5        1016        25.5        27.7        26.6
1   26.7        1048        26.3        53.5        39.9
2   25.8        1016        25.5        27.7        26.6
3   53.5        1048        26.3        53.5        39.9
4   29.3        1064        29.3        29.3        29.3
5   27.7        1016        25.5        27.7        26.6

Body:
The describe method, as given in YOBEN_S's solution, will compute more statistics than is required, including count, std, and dtypes. See here.

We can get around this by using the agg method.

df.merge(df.groupby('groupId')['avg'].agg([min, max, 'mean']), on='groupId')

# output
avg groupId min max mean
0   25.5    1016    25.5    27.7    26.333333
1   26.7    1048    26.7    53.5    40.100000
2   25.8    1016    25.5    27.7    26.333333
3   53.5    1048    26.7    53.5    40.100000
4   29.3    1064    29.3    29.3    29.300000
5   27.7    1016    25.5    27.7    26.333333

Speed Comparison

Approach 1

%%timeit -n 1000

df.merge(df.groupby('groupId').avg.describe()[['mean','min','max']].reset_index(),how='left')

9.6 ms ± 123 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Approach 2

%%timeit -n 1000

df.merge(df.groupby('groupId')['avg'].agg([min, max, 'mean']), on='groupId')

3.42 ms ± 74.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Approach 3

Additionally, we can get a slight speedup by converting df.merge to df.join.

2.96 ms ± 29.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)


问:
get the unique values from the associative array in PHP?
I am having the array like below

```<code>Array
(
    [0] => Array
        (
            [catid] => 3
            [parent_id] => 1
            [catname] => Uncategorized
            [catdesc] =>
            [nleft] => 20
            [nright] => 21
            [nlevel] => 1
        )

    [1] => Array
        (
            [catid] => 5
            [parent_id] => 2
            [catname] => Category 2
            [catdesc] =>
            [nleft] => 7
            [nright] => 8
            [nlevel] => 2
        )

    [2] => Array
        (
            [catid] => 3
            [parent_id] => 1
            [catname] => Uncategorized
            [catdesc] =>
            [nleft] => 20
            [nright] => 21
            [nlevel] => 1
        )

    [3] => Array
        (
            [catid] => 3
            [parent_id] => 1
            [catname] => Uncategorized
            [catdesc] =>
            [nleft] => 20
            [nright] => 21
            [nlevel] => 1
        )

    [4] => Array
        (
            [catid] => 7
            [parent_id] => 2
            [catname] => Flower
            [catdesc] =>
            [nleft] => 11
            [nright] => 18
            [nlevel] => 2
        )

    [5] => Array
        (
            [catid] => 8
            [parent_id] => 7
            [catname] => Lillies
            [catdesc] =>
            [nleft] => 12
            [nright] => 13
            [nlevel] => 3
        )

    [6] => Array
        (
            [catid] => 10
            [parent_id] => 7
            [catname] => Jasmine
            [catdesc] =>
            [nleft] => 16
            [nright] => 17
            [nlevel] => 3
        )

    [7] => Array
        (
            [catid] => 7
            [parent_id] => 2
            [catname] => Flower
            [catdesc] =>
            [nleft] => 11
            [nright] => 18
            [nlevel] => 2
        )

    [8] => Array
        (
            [catid] => 8
            [parent_id] => 7
            [catname] => Lillies
            [catdesc] =>
            [nleft] => 12
            [nright] => 13
            [nlevel] => 3
        )

    [9] => Array
        (
            [catid] => 10
            [parent_id] => 7
            [catname] => Jasmine
            [catdesc] =>
            [nleft] => 16
            [nright] => 17
            [nlevel] => 3
        )

    [10] => Array
        (
            [catid] => 3
            [parent_id] => 1
            [catname] => Uncategorized
            [catdesc] =>
            [nleft] => 20
            [nright] => 21
            [nlevel] => 1
        )

    [11] => Array
        (
            [catid] => 3
            [parent_id] => 1
            [catname] => Uncategorized
            [catdesc] =>
            [nleft] => 20
            [nright] => 21
            [nlevel] => 1
        )

    [12] => Array
        (
            [catid] => 10
            [parent_id] => 7
            [catname] => Jasmine
            [catdesc] =>
            [nleft] => 16
            [nright] => 17
            [nlevel] => 3
        )

    [13] => Array
        (
            [catid] => 3
            [parent_id] => 1
            [catname] => Uncategorized
            [catdesc] =>
            [nleft] => 20
            [nright] => 21
            [nlevel] => 1
        )

    [14] => Array
        (
            [catid] => 8
            [parent_id] => 7
            [catname] => Lillies
            [catdesc] =>
            [nleft] => 12
            [nright] => 13
            [nlevel] => 3
        )

)
</code>```

From this array I want to get the Unique Arrays.ie. If catId is same it needs to eliminate from the list.
How can I do this?

答:
If you're using an older version:</p>

```<code>$out = array();
foreach ($arr as $row) {
    $out[$row['catid']] = $row;
}
$array = array_values($out); // only required if you mind the new array being assoc
</code>```

Body:
I am having the array like below

Array
(
    [0] => Array
        (
            [catid] => 3
            [parent_id] => 1
            [catname] => Uncategorized
            [catdesc] =>
            [nleft] => 20
            [nright] => 21
            [nlevel] => 1
        )

    [1] => Array
        (
            [catid] => 5
            [parent_id] => 2
            [catname] => Category 2
            [catdesc] =>
            [nleft] => 7
            [nright] => 8
            [nlevel] => 2
        )

    [2] => Array
        (
            [catid] => 3
            [parent_id] => 1
            [catname] => Uncategorized
            [catdesc] =>
            [nleft] => 20
            [nright] => 21
            [nlevel] => 1
        )

    [3] => Array
        (
            [catid] => 3
            [parent_id] => 1
            [catname] => Uncategorized
            [catdesc] =>
            [nleft] => 20
            [nright] => 21
            [nlevel] => 1
        )

    [4] => Array
        (
            [catid] => 7
            [parent_id] => 2
            [catname] => Flower
            [catdesc] =>
            [nleft] => 11
            [nright] => 18
            [nlevel] => 2
        )

    [5] => Array
        (
            [catid] => 8
            [parent_id] => 7
            [catname] => Lillies
            [catdesc] =>
            [nleft] => 12
            [nright] => 13
            [nlevel] => 3
        )

    [6] => Array
        (
            [catid] => 10
            [parent_id] => 7
            [catname] => Jasmine
            [catdesc] =>
            [nleft] => 16
            [nright] => 17
            [nlevel] => 3
        )

    [7] => Array
        (
            [catid] => 7
            [parent_id] => 2
            [catname] => Flower
            [catdesc] =>
            [nleft] => 11
            [nright] => 18
            [nlevel] => 2
        )

    [8] => Array
        (
            [catid] => 8
            [parent_id] => 7
            [catname] => Lillies
            [catdesc] =>
            [nleft] => 12
            [nright] => 13
            [nlevel] => 3
        )

    [9] => Array
        (
            [catid] => 10
            [parent_id] => 7
            [catname] => Jasmine
            [catdesc] =>
            [nleft] => 16
            [nright] => 17
            [nlevel] => 3
        )

    [10] => Array
        (
            [catid] => 3
            [parent_id] => 1
            [catname] => Uncategorized
            [catdesc] =>
            [nleft] => 20
            [nright] => 21
            [nlevel] => 1
        )

    [11] => Array
        (
            [catid] => 3
            [parent_id] => 1
            [catname] => Uncategorized
            [catdesc] =>
            [nleft] => 20
            [nright] => 21
            [nlevel] => 1
        )

    [12] => Array
        (
            [catid] => 10
            [parent_id] => 7
            [catname] => Jasmine
            [catdesc] =>
            [nleft] => 16
            [nright] => 17
            [nlevel] => 3
        )

    [13] => Array
        (
            [catid] => 3
            [parent_id] => 1
            [catname] => Uncategorized
            [catdesc] =>
            [nleft] => 20
            [nright] => 21
            [nlevel] => 1
        )

    [14] => Array
        (
            [catid] => 8
            [parent_id] => 7
            [catname] => Lillies
            [catdesc] =>
            [nleft] => 12
            [nright] => 13
            [nlevel] => 3
        )

)

From this array I want to get the Unique Arrays.ie. If catId is same it needs to eliminate from the list.
How can I do this?

Body:
If you're using an older version:

$out = array();
foreach ($arr as $row) {
    $out[$row['catid']] = $row;
}
$array = array_values($out); // only required if you mind the new array being assoc


问:
Calling firebase functions returns null
I am calling the Functions function to get user information, but it returns null.
Please tell me the solution.

workspace/functions/src/index.ts

```<code>exports.getUser = functions.https.onCall((data, context) => {
  admin.database().ref(`user/${data.userId}`)
    .on('value', (snapshot) => {
      if (snapshot) return snapshot.val();
    });
});
</code>```

workspace/src/app/sample.component.ts

```<code>firebase.functions().httpsCallable('getUser')({
  userId: profile.userId
}).then(data => {
  console.log(data);
}).catch(error => {
  alert(error);
});
</code>```

答:
First of all, you should be using once() instead of on() for your query.  on() sets up a persistent listener, which is not good in Cloud Functions, because it might leak the listener and cost you money.  once() performs a single query and returns a promise that you can work with.

Second, you should return a promise from your function that resolves with the data you want to return to the client.  This is required by callable type triggers.  Right now, you're returning nothing from the top-level function.

Third, you should return a value in every code path through your function.

```<code>exports.getUser = functions.https.onCall((data, context) => {
  return admin.database().ref(`user/${data.userId}`).once('value')
  .then(snapshot => {
    if (snapshot) {
      return snapshot.val();
    }
    else {
      // indicates that there was no data for the userId
      return null;
    }
  });
});
</code>```

Title: Calling firebase functions returns null

Body:
I am calling the Functions function to get user information, but it returns null.
Please tell me the solution.

workspace/functions/src/index.ts

exports.getUser = functions.https.onCall((data, context) => {
  admin.database().ref(`user/${data.userId}`)
    .on('value', (snapshot) => {
      if (snapshot) return snapshot.val();
    });
});

workspace/src/app/sample.component.ts

firebase.functions().httpsCallable('getUser')({
  userId: profile.userId
}).then(data => {
  console.log(data);
}).catch(error => {
  alert(error);
});

Body:
First of all, you should be using once() instead of on() for your query.  on() sets up a persistent listener, which is not good in Cloud Functions, because it might leak the listener and cost you money.  once() performs a single query and returns a promise that you can work with.

Second, you should return a promise from your function that resolves with the data you want to return to the client.  This is required by callable type triggers.  Right now, you're returning nothing from the top-level function.

Third, you should return a value in every code path through your function.

exports.getUser = functions.https.onCall((data, context) => {
  return admin.database().ref(`user/${data.userId}`).once('value')
  .then(snapshot => {
    if (snapshot) {
      return snapshot.val();
    }
    else {
      // indicates that there was no data for the userId
      return null;
    }
  });
});


问:
Not able to flip the SVG circle from the Z-Axis
I am trying to flip the red circle from the z-axis, but it is flipping from the y-axis only. In the below code, I am rotating the red circle.

.processicon:hover .flip-circle, .processicon:hover .fil2{
  transform-origin: 56% 56%;
  transform: rotate3d(0, 150, 0, 180deg);
 }

 .flip-circle, .fil2{
  transition: 0.4s linear;
 }```
<pre class="snippet-code-html lang-html prettyprint-override"><code><?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Creator: CorelDRAW X7 -->
<svg class="processicon" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="150px"  version="1.1" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd"
viewBox="0 0 1284 1309"
 xmlns:xlink="http://www.w3.org/1999/xlink">
 <defs>
  <style type="text/css">
   <![CDATA[
    .fil1 {fill:#BF1E2E}
    .fil2 {fill:white}
    .fil0 {fill:url(#id0)}
   ]]>
  </style>
  <linearGradient id="id0" gradientUnits="userSpaceOnUse" x1="194.719" y1="514.919" x2="1089.02" y2="793.777">
   <stop offset="0" style="stop-opacity:1; stop-color:#2056A6"/>
   <stop offset="1" style="stop-opacity:1; stop-color:#22356A"/>
  </linearGradient>
 </defs>
 <g id="Layer_x0020_1">
  <metadata id="CorelCorpID_0Corel-Layer"/>
  <g id="_681339696">
   <path class="fil0" d="M642 0c54,0 106,7 156,19 -26,-4 -53,-6 -80,-6 -162,0 -306,74 -403,189 -114,147 -169,320 -90,552 78,200 269,340 493,340 292,0 530,-242 530,-540 0,-77 -16,-150 -44,-216 51,94 80,202 80,316 0,362 -288,655 -642,655 -280,0 -518,-183 -606,-437 -7,-22 -14,-44 -19,-66l0 0 0 -1c-44,-191 -2,-395 118,-552 10,-14 21,-27 32,-39l1 0 0 0c117,-132 286,-214 474,-214z"/>
   <ellipse class="fil1 flip-circle" cx="715" cy="556" rx="504" ry="514"/>
   <g>
    <g>
     <path class="fil2" d="M1040 809l-5 -92c-3,-41 -30,-77 -69,-91l-20 -7 -7 -2 -107 -38c-1,-1 -1,-1 -2,-1 0,0 0,0 0,0 -1,0 -1,0 -1,0 0,0 0,0 -1,0 0,0 0,0 0,0 0,0 -1,0 -1,0 0,0 0,0 0,0 -1,0 -1,0 -1,0 -1,0 -2,0 -3,0 0,0 0,0 0,0 -2,0 -5,1 -7,3 0,0 0,0 -1,0 0,0 0,0 0,1 0,0 -1,0 -1,0l-34 -10 0 -26c32,-21 57,-60 59,-96l0 0c15,0 26,-12 26,-26l0 -24c0,-3 -1,-6 -2,-9 7,-3 11,-10 11,-17l0 -14c0,-9 -7,-18 -16,-19l0 -4c0,-1 0,-2 0,-3 0,-12 -2,-23 -6,-34 -1,-5 -7,-8 -12,-7 -5,2 -8,7 -6,12 3,10 4,19 5,29 0,1 0,2 0,3l0 13c0,5 4,10 9,10l6 0c0,0 1,0 1,0l0 14c0,0 -1,0 -1,0l-279 0c0,0 0,0 0,0l0 -14c0,0 0,0 0,0l6 0c6,0 10,-5 10,-10l0 -13c0,-1 0,-2 0,-3 1,-50 38,-93 86,-101l0 35 0 0c0,8 4,16 9,22 0,0 0,0 1,0 0,0 0,0 0,1 6,5 13,9 22,9l0 0 11 0 0 0c9,0 17,-4 23,-9 0,-1 0,-1 0,-1 0,0 0,0 0,0 6,-6 9,-14 9,-22l0 0 0 -35c27,4 50,19 66,41 3,4 9,5 14,2 4,-3 5,-9 2,-13 -21,-28 -51,-46 -85,-50 -5,-11 -16,-18 -29,-18l-11 0c-12,0 -23,7 -28,18 -29,3 -55,16 -75,37 -21,23 -33,52 -34,84 0,1 0,2 0,3l0 4c-9,1 -16,10 -16,19l0 14c0,7 4,14 10,17 -1,3 -1,6 -1,9l0 24c0,14 11,26 25,26l1 0c1,36 26,75 58,97l0 25 -33 10c-1,0 -1,0 -1,0 0,-1 -1,-1 -1,-1 0,0 0,0 0,0 -3,-2 -5,-3 -8,-3 0,0 0,0 0,0 -1,0 -1,0 -2,0 -1,0 -1,0 -1,0 0,0 0,0 0,0 -1,0 -1,0 -1,0 0,0 -1,0 -1,0 0,0 0,0 0,0 -1,0 -1,0 -1,0 0,0 -1,0 -1,0 0,0 -1,0 -1,1l-93 32 -21 8 0 0 -20 7c-39,14 -66,50 -69,91l-1 11c0,6 4,10 9,10 5,1 10,-3 10,-8l1 -11c2,-34 24,-64 56,-75l8 -3 0 181 -59 0c-3,0 -6,-1 -8,-4 -2,-2 -3,-5 -3,-8l3 -42c0,-5 -4,-10 -9,-10 -5,0 -10,4 -10,9l-3 42c0,8 3,16 8,22 6,6 14,10 22,10l68 0 72 0 311 0 73 0 67 0c9,0 17,-4 22,-10 6,-6 9,-14 8,-22zm-201 -415l0 0c4,0 7,2 7,6l0 24c0,4 -3,6 -7,6l0 0 0 -36zm-143 -167c0,-1 0,-2 1,-3 0,0 0,0 0,0 1,-6 6,-10 12,-10l11 0c6,0 11,4 13,10 0,0 0,0 0,0 0,1 0,2 0,3l0 41c0,3 -1,6 -3,9 0,0 0,0 0,0 -1,0 -1,0 -1,0 -2,2 -5,4 -9,4l-11 0c-3,0 -6,-2 -9,-4 0,0 0,0 0,0 0,0 0,0 0,0 -2,-3 -4,-6 -4,-9l0 -41zm-105 203l-1 0c-3,0 -6,-2 -6,-6l0 -24c0,-4 3,-6 6,-6l1 0 0 36zm-41 392l-53 0 0 -187 34 -12 19 -7 0 206zm60 -376l0 -6 0 -46 210 0 0 46 0 0 0 6c0,33 -27,72 -58,89 0,0 0,0 0,0 -1,1 -2,1 -3,2 0,0 -1,0 -1,0 -2,1 -4,2 -6,3 0,0 -1,0 -1,0 -1,0 -2,1 -2,1 -1,0 -1,0 -1,0 -1,1 -3,1 -4,1l-1 0c-2,1 -4,2 -6,2 -9,2 -16,3 -23,3 -8,0 -16,-1 -29,-5 -1,0 -2,0 -3,-1 -1,0 -1,0 -1,0 -1,0 -2,0 -3,-1 0,0 0,0 0,0 -3,-1 -5,-2 -7,-3 0,0 0,0 0,0 -33,-16 -61,-57 -61,-91zm47 144c7,-2 11,-9 11,-16l0 -17c1,0 2,0 3,1 0,0 1,0 1,0 1,1 2,1 3,1 1,1 1,1 1,1 2,0 3,1 4,1 4,1 7,1 9,2 1,0 2,0 3,1 0,0 0,0 0,0 8,1 15,2 22,2 0,0 0,0 0,0 0,0 0,0 0,0 8,0 15,-1 24,-3 3,0 6,-1 10,-2l1 0c1,-1 3,-1 4,-1 0,-1 1,-1 1,-1 1,0 2,0 3,-1 0,0 1,0 1,0 1,-1 2,-1 3,-1l0 17c0,7 5,14 12,16l25 8c0,0 0,0 0,0 -1,1 -2,2 -4,3 0,0 0,0 0,1 -2,1 -3,2 -4,3 0,0 -1,0 -1,0 -1,1 -3,2 -4,3 0,0 0,0 -1,0 -1,1 -2,2 -4,3 0,0 0,0 0,0 -2,1 -3,2 -4,3 -1,0 -1,0 -1,0 -2,1 -3,1 -4,2 -1,0 -1,0 -1,1 -2,0 -3,1 -5,2 0,0 0,0 -1,0 -1,1 -2,1 -4,2 0,0 -1,0 -1,0 -1,1 -3,1 -4,2 -1,0 -1,0 -1,0 -2,0 -3,1 -5,1 0,0 0,0 0,0 -2,1 -4,1 -5,2 0,0 -1,0 -1,0 -1,0 -3,0 -5,1 0,0 0,0 -1,0 -1,0 -3,0 -4,1 -1,0 -1,0 -1,0 -2,0 -4,0 -5,0 -1,0 -1,0 -1,0 -2,1 -3,1 -5,1 0,0 -1,0 -1,0 -2,0 -3,0 -5,0 0,0 0,0 0,0 -2,0 -4,0 -6,0 0,0 0,0 0,0 -2,0 -4,0 -5,-1 -1,0 -1,0 -1,0 -2,0 -3,0 -5,0 0,0 -1,0 -1,0 -2,-1 -3,-1 -5,-1 0,0 0,0 -1,0 -1,-1 -3,-1 -5,-1 0,0 0,0 0,0 -4,-1 -7,-2 -10,-3 -1,0 -1,0 -1,0 -1,-1 -3,-1 -5,-2 0,0 0,0 0,0 -2,-1 -3,-1 -5,-2 0,0 0,0 -1,0 -1,-1 -3,-2 -4,-2 0,-1 -1,-1 -1,-1 -1,-1 -3,-1 -4,-2 -1,0 -1,0 -1,0 -3,-2 -6,-4 -9,-6 0,0 0,0 0,0 -2,-1 -3,-2 -5,-3 0,0 0,0 0,0 -2,-1 -3,-2 -4,-3 0,-1 -1,-1 -1,-1 -1,-1 -2,-2 -4,-3 0,0 0,0 0,0l26 -8zm-54 7l8 8c28,28 65,43 104,43 0,0 0,0 0,0 0,0 0,0 0,0 24,0 47,-6 68,-17 12,-6 23,-14 32,-23 0,0 0,0 0,0 1,-1 2,-1 2,-2 0,0 1,0 1,-1l0 0 8 -8 8 3 3 1 -12 12c-30,29 -69,45 -110,45 -42,0 -81,-16 -110,-45l-12 -12 10 -4zm258 225l-292 0 0 -213 4 -1 18 19c0,0 0,0 0,0 33,32 77,50 124,50 46,0 90,-18 123,-50 0,0 0,0 0,0l19 -19 4 1 0 213zm72 0l-53 0 0 -206 19 7 34 12 0 187zm85 -4c-2,3 -5,4 -8,4l-58 0 0 -181 7 3c32,11 54,41 57,75l5 91c1,3 0,6 -3,8z"/>
    </g>
   </g>
  </g>
 </g>
</svg></code>```

Any help is much appreciated.

答:
try to use it like this: rotate3d(360, 360, 360, 1turn); and just play with the values until you get the result you need which is not very clear in the question.

or you can apply multiple transforms like this:

transform: rotate3d(0, 150, 0, 180deg) rotate3d(150, 0, 0, 180deg);

Also, some docs: https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/rotate3d

Body:
I am trying to flip the red circle from the z-axis, but it is flipping from the y-axis only. In the below code, I am rotating the red circle.

.processicon:hover .flip-circle, .processicon:hover .fil2{
  transform-origin: 56% 56%;
  transform: rotate3d(0, 150, 0, 180deg);
 }

 .flip-circle, .fil2{
  transition: 0.4s linear;
 }

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg class="processicon" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="150px"  version="1.1" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd"
viewBox="0 0 1284 1309"
 xmlns:xlink="http://www.w3.org/1999/xlink">
 <defs>

  <linearGradient id="id0" gradientUnits="userSpaceOnUse" x1="194.719" y1="514.919" x2="1089.02" y2="793.777">
   <stop offset="0" style="stop-opacity:1; stop-color:#2056A6"/>
   <stop offset="1" style="stop-opacity:1; stop-color:#22356A"/>
  </linearGradient>
 </defs>
 <g id="Layer_x0020_1">
  <metadata id="CorelCorpID_0Corel-Layer"/>
  <g id="_681339696">
   <path class="fil0" d="M642 0c54,0 106,7 156,19 -26,-4 -53,-6 -80,-6 -162,0 -306,74 -403,189 -114,147 -169,320 -90,552 78,200 269,340 493,340 292,0 530,-242 530,-540 0,-77 -16,-150 -44,-216 51,94 80,202 80,316 0,362 -288,655 -642,655 -280,0 -518,-183 -606,-437 -7,-22 -14,-44 -19,-66l0 0 0 -1c-44,-191 -2,-395 118,-552 10,-14 21,-27 32,-39l1 0 0 0c117,-132 286,-214 474,-214z"/>
   <ellipse class="fil1 flip-circle" cx="715" cy="556" rx="504" ry="514"/>
   <g>
    <g>
     <path class="fil2" d="M1040 809l-5 -92c-3,-41 -30,-77 -69,-91l-20 -7 -7 -2 -107 -38c-1,-1 -1,-1 -2,-1 0,0 0,0 0,0 -1,0 -1,0 -1,0 0,0 0,0 -1,0 0,0 0,0 0,0 0,0 -1,0 -1,0 0,0 0,0 0,0 -1,0 -1,0 -1,0 -1,0 -2,0 -3,0 0,0 0,0 0,0 -2,0 -5,1 -7,3 0,0 0,0 -1,0 0,0 0,0 0,1 0,0 -1,0 -1,0l-34 -10 0 -26c32,-21 57,-60 59,-96l0 0c15,0 26,-12 26,-26l0 -24c0,-3 -1,-6 -2,-9 7,-3 11,-10 11,-17l0 -14c0,-9 -7,-18 -16,-19l0 -4c0,-1 0,-2 0,-3 0,-12 -2,-23 -6,-34 -1,-5 -7,-8 -12,-7 -5,2 -8,7 -6,12 3,10 4,19 5,29 0,1 0,2 0,3l0 13c0,5 4,10 9,10l6 0c0,0 1,0 1,0l0 14c0,0 -1,0 -1,0l-279 0c0,0 0,0 0,0l0 -14c0,0 0,0 0,0l6 0c6,0 10,-5 10,-10l0 -13c0,-1 0,-2 0,-3 1,-50 38,-93 86,-101l0 35 0 0c0,8 4,16 9,22 0,0 0,0 1,0 0,0 0,0 0,1 6,5 13,9 22,9l0 0 11 0 0 0c9,0 17,-4 23,-9 0,-1 0,-1 0,-1 0,0 0,0 0,0 6,-6 9,-14 9,-22l0 0 0 -35c27,4 50,19 66,41 3,4 9,5 14,2 4,-3 5,-9 2,-13 -21,-28 -51,-46 -85,-50 -5,-11 -16,-18 -29,-18l-11 0c-12,0 -23,7 -28,18 -29,3 -55,16 -75,37 -21,23 -33,52 -34,84 0,1 0,2 0,3l0 4c-9,1 -16,10 -16,19l0 14c0,7 4,14 10,17 -1,3 -1,6 -1,9l0 24c0,14 11,26 25,26l1 0c1,36 26,75 58,97l0 25 -33 10c-1,0 -1,0 -1,0 0,-1 -1,-1 -1,-1 0,0 0,0 0,0 -3,-2 -5,-3 -8,-3 0,0 0,0 0,0 -1,0 -1,0 -2,0 -1,0 -1,0 -1,0 0,0 0,0 0,0 -1,0 -1,0 -1,0 0,0 -1,0 -1,0 0,0 0,0 0,0 -1,0 -1,0 -1,0 0,0 -1,0 -1,0 0,0 -1,0 -1,1l-93 32 -21 8 0 0 -20 7c-39,14 -66,50 -69,91l-1 11c0,6 4,10 9,10 5,1 10,-3 10,-8l1 -11c2,-34 24,-64 56,-75l8 -3 0 181 -59 0c-3,0 -6,-1 -8,-4 -2,-2 -3,-5 -3,-8l3 -42c0,-5 -4,-10 -9,-10 -5,0 -10,4 -10,9l-3 42c0,8 3,16 8,22 6,6 14,10 22,10l68 0 72 0 311 0 73 0 67 0c9,0 17,-4 22,-10 6,-6 9,-14 8,-22zm-201 -415l0 0c4,0 7,2 7,6l0 24c0,4 -3,6 -7,6l0 0 0 -36zm-143 -167c0,-1 0,-2 1,-3 0,0 0,0 0,0 1,-6 6,-10 12,-10l11 0c6,0 11,4 13,10 0,0 0,0 0,0 0,1 0,2 0,3l0 41c0,3 -1,6 -3,9 0,0 0,0 0,0 -1,0 -1,0 -1,0 -2,2 -5,4 -9,4l-11 0c-3,0 -6,-2 -9,-4 0,0 0,0 0,0 0,0 0,0 0,0 -2,-3 -4,-6 -4,-9l0 -41zm-105 203l-1 0c-3,0 -6,-2 -6,-6l0 -24c0,-4 3,-6 6,-6l1 0 0 36zm-41 392l-53 0 0 -187 34 -12 19 -7 0 206zm60 -376l0 -6 0 -46 210 0 0 46 0 0 0 6c0,33 -27,72 -58,89 0,0 0,0 0,0 -1,1 -2,1 -3,2 0,0 -1,0 -1,0 -2,1 -4,2 -6,3 0,0 -1,0 -1,0 -1,0 -2,1 -2,1 -1,0 -1,0 -1,0 -1,1 -3,1 -4,1l-1 0c-2,1 -4,2 -6,2 -9,2 -16,3 -23,3 -8,0 -16,-1 -29,-5 -1,0 -2,0 -3,-1 -1,0 -1,0 -1,0 -1,0 -2,0 -3,-1 0,0 0,0 0,0 -3,-1 -5,-2 -7,-3 0,0 0,0 0,0 -33,-16 -61,-57 -61,-91zm47 144c7,-2 11,-9 11,-16l0 -17c1,0 2,0 3,1 0,0 1,0 1,0 1,1 2,1 3,1 1,1 1,1 1,1 2,0 3,1 4,1 4,1 7,1 9,2 1,0 2,0 3,1 0,0 0,0 0,0 8,1 15,2 22,2 0,0 0,0 0,0 0,0 0,0 0,0 8,0 15,-1 24,-3 3,0 6,-1 10,-2l1 0c1,-1 3,-1 4,-1 0,-1 1,-1 1,-1 1,0 2,0 3,-1 0,0 1,0 1,0 1,-1 2,-1 3,-1l0 17c0,7 5,14 12,16l25 8c0,0 0,0 0,0 -1,1 -2,2 -4,3 0,0 0,0 0,1 -2,1 -3,2 -4,3 0,0 -1,0 -1,0 -1,1 -3,2 -4,3 0,0 0,0 -1,0 -1,1 -2,2 -4,3 0,0 0,0 0,0 -2,1 -3,2 -4,3 -1,0 -1,0 -1,0 -2,1 -3,1 -4,2 -1,0 -1,0 -1,1 -2,0 -3,1 -5,2 0,0 0,0 -1,0 -1,1 -2,1 -4,2 0,0 -1,0 -1,0 -1,1 -3,1 -4,2 -1,0 -1,0 -1,0 -2,0 -3,1 -5,1 0,0 0,0 0,0 -2,1 -4,1 -5,2 0,0 -1,0 -1,0 -1,0 -3,0 -5,1 0,0 0,0 -1,0 -1,0 -3,0 -4,1 -1,0 -1,0 -1,0 -2,0 -4,0 -5,0 -1,0 -1,0 -1,0 -2,1 -3,1 -5,1 0,0 -1,0 -1,0 -2,0 -3,0 -5,0 0,0 0,0 0,0 -2,0 -4,0 -6,0 0,0 0,0 0,0 -2,0 -4,0 -5,-1 -1,0 -1,0 -1,0 -2,0 -3,0 -5,0 0,0 -1,0 -1,0 -2,-1 -3,-1 -5,-1 0,0 0,0 -1,0 -1,-1 -3,-1 -5,-1 0,0 0,0 0,0 -4,-1 -7,-2 -10,-3 -1,0 -1,0 -1,0 -1,-1 -3,-1 -5,-2 0,0 0,0 0,0 -2,-1 -3,-1 -5,-2 0,0 0,0 -1,0 -1,-1 -3,-2 -4,-2 0,-1 -1,-1 -1,-1 -1,-1 -3,-1 -4,-2 -1,0 -1,0 -1,0 -3,-2 -6,-4 -9,-6 0,0 0,0 0,0 -2,-1 -3,-2 -5,-3 0,0 0,0 0,0 -2,-1 -3,-2 -4,-3 0,-1 -1,-1 -1,-1 -1,-1 -2,-2 -4,-3 0,0 0,0 0,0l26 -8zm-54 7l8 8c28,28 65,43 104,43 0,0 0,0 0,0 0,0 0,0 0,0 24,0 47,-6 68,-17 12,-6 23,-14 32,-23 0,0 0,0 0,0 1,-1 2,-1 2,-2 0,0 1,0 1,-1l0 0 8 -8 8 3 3 1 -12 12c-30,29 -69,45 -110,45 -42,0 -81,-16 -110,-45l-12 -12 10 -4zm258 225l-292 0 0 -213 4 -1 18 19c0,0 0,0 0,0 33,32 77,50 124,50 46,0 90,-18 123,-50 0,0 0,0 0,0l19 -19 4 1 0 213zm72 0l-53 0 0 -206 19 7 34 12 0 187zm85 -4c-2,3 -5,4 -8,4l-58 0 0 -181 7 3c32,11 54,41 57,75l5 91c1,3 0,6 -3,8z"/>
    </g>
   </g>
  </g>
 </g>
</svg>

Any help is much appreciated.


问:
How can I subset into dataframes based on unique variable using a for loop?
want to subset a dataset into 4 categories (based on the 4 unique categories) using a for loop. I've tried some subsetting and haven't been successful.

```<code>ID Region Other
1  North    x
2  South    y
3  West     z
4  East     l
</code>```

I want to subset into 4 dataframes subset by "region"

I've tried the following but am not quite getting it! Any help would be greatly appreciated.

```<code>for region in test.region.unique():
    reg = test[test == region]
</code>```

答:
I think best practice would be to create a dictionary with each df entry like this:</p>

```<code>df_dict = {x:df.loc[df.Region == x] for x in df.Region}
</code>```

Body:
want to subset a dataset into 4 categories (based on the 4 unique categories) using a for loop. I've tried some subsetting and haven't been successful.

ID Region Other
1  North    x
2  South    y
3  West     z
4  East     l

I want to subset into 4 dataframes subset by "region"

I've tried the following but am not quite getting it! Any help would be greatly appreciated.

for region in test.region.unique():
    reg = test[test == region]

Body:
I think best practice would be to create a dictionary with each df entry like this:

df_dict = {x:df.loc[df.Region == x] for x in df.Region}


问:
KotlinNullPointerException when rotating the screen on Fragment with map and localization
I have a kotlin.KotlinNullPointerException at line:

```<code>val locationmanager=context!!.getSystemService(Context.LOCATION_SERVICE) as LocationManager
</code>```

When I rotate my screen. This line is in function in:

```<code>class MyMapFragment: Fragment(),OnMapReadyCallback
</code>```

答:
Fragment can access context only after onAttach lifecycle method called, because it get attached to it's host activity in this lifecycle method. So, to avoid NPE you need
in fragment

```<code>lateinit var locationmanager: LocationManager

override fun onCreateView(inflater: LayoutInflater,
                          container: ViewGroup?,
                          savedInstanceState: Bundle?): View? {
    locationmanager = context!!.getSystemService(Context.LOCATION_SERVICE) as LocationManager
    return inflater.inflate(R.layout.your_fragment_layout, container, false)
}
</code>```

Body:
I have a kotlin.KotlinNullPointerException at line:

val locationmanager=context!!.getSystemService(Context.LOCATION_SERVICE) as LocationManager

When I rotate my screen. This line is in function in:

class MyMapFragment: Fragment(),OnMapReadyCallback

Body:
Fragment can access context only after onAttach lifecycle method called, because it get attached to it's host activity in this lifecycle method. So, to avoid NPE you need
in fragment

lateinit var locationmanager: LocationManager

override fun onCreateView(inflater: LayoutInflater,
                          container: ViewGroup?,
                          savedInstanceState: Bundle?): View? {
    locationmanager = context!!.getSystemService(Context.LOCATION_SERVICE) as LocationManager
    return inflater.inflate(R.layout.your_fragment_layout, container, false)
}