问:
How to efficiently edit an item which is deep inside the data set, displayed as react component?
I have a set, that is n levels deep, and on its last level, there is a data row, that contains a value. Displaying that value is easy, but once I edit it, the re-rendering of the whole set takes a lot of time.
Since to edit it, I have to pass the new value, and item's index back to the highest level.

The code below is just an exemplary, since I'm asking about the possible approach.

High level component:

```<code>const HighComponent = () => {
   const [data, setData] = useState([]); //array of objects

   render <TableWithData data={data} onChange={setData}/>
}
</code>```

Component that is n-level deep:

```<code>const FinalComponent = ({item, itemsIndexInPreviousArray, onChangeFromPreviousComponent}) => {
    // this kind of function will assemble the data from the lowest point and return it back
    // to the highest component, that will receive the final data to change, but this kind of
    // approach will take n*itemsNumber re-renders and time-wise is quiet slow.
    const changeThisItem = (newValue) => {
         onChangeFromPreviousComponent(newValue, itemsIndexInPreviousArray)
    }
    return (
         <>
             <input value={item} onChange={e => changeThisItem(e.target.value)}/>
         </>
    );
}
</code>```

I would use memoization, but this components are for display only, and they have to trigger an endpoint to update the finalData(top level data) anyway. Whether it is onChange event, or bulk trigger.

Any suggestions would be appreciated.

答:
The need to pass data several levels up (and, probably, consume by several components), indicates the fact that you might need something more sophisticated to manage your state.

You may consider Redux. It may solve your problem in a nice and effortless manner.

Check out the following live-snippet, paying attention that intermediate component is not getting re-rendered as you type:

const { useEffect } = React,
      { render } = ReactDOM,
      { createStore } = Redux,
      { Provider, useSelector, useDispatch } = ReactRedux

const defaultState = {data:''},
      appReducer = (state=defaultState, action) => {
        switch(action.type){
          case 'SET_DATA': {
            return {...state, data: action.payload}
          }
          default: return state
        }
      },
      store = createStore(appReducer)

const Parent = ({children}) => {
  const data = useSelector(({data}) => data)
  useEffect(() => console.log('Parent is rendered'))
  return (

Current data value is: {data}

      {children}

  )
}

const Intermediate = ({children}) => {
  useEffect(() => console.log('Intermediate is rendered'))
  return (

{children}

  )
}

const Child = () => {
  const dispatch = useDispatch()
  useEffect(() => console.log('Child is rendered'))
  return (
    <input
        onKeyUp={({target:{value}}) => dispatch({
          type: 'SET_DATA',
          payload: value
        })}
    />
  )
}

render (
  <Provider {...{store}} >
    <Parent>
      <Intermediate>
        <Child />
      </Intermediate>
    </Parent>
  </Provider>,
  document.getElementById('root')
)```
<pre class="snippet-code-html lang-html prettyprint-override"><code><script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script><script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.4/redux.min.js"></script><script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.1.1/react-redux.min.js"></script><div id="root"></div></code>```

Body:
I have a set, that is n levels deep, and on its last level, there is a data row, that contains a value. Displaying that value is easy, but once I edit it, the re-rendering of the whole set takes a lot of time.
Since to edit it, I have to pass the new value, and item's index back to the highest level.

The code below is just an exemplary, since I'm asking about the possible approach.

High level component:

const HighComponent = () => {
   const [data, setData] = useState([]); //array of objects

   render <TableWithData data={data} onChange={setData}/>
}

Component that is n-level deep:

const FinalComponent = ({item, itemsIndexInPreviousArray, onChangeFromPreviousComponent}) => {
    // this kind of function will assemble the data from the lowest point and return it back
    // to the highest component, that will receive the final data to change, but this kind of
    // approach will take n*itemsNumber re-renders and time-wise is quiet slow.
    const changeThisItem = (newValue) => {
         onChangeFromPreviousComponent(newValue, itemsIndexInPreviousArray)
    }
    return (
         <>
             <input value={item} onChange={e => changeThisItem(e.target.value)}/>
         </>
    );
}

I would use memoization, but this components are for display only, and they have to trigger an endpoint to update the finalData(top level data) anyway. Whether it is onChange event, or bulk trigger.

Any suggestions would be appreciated.

Body:
The need to pass data several levels up (and, probably, consume by several components), indicates the fact that you might need something more sophisticated to manage your state.

You may consider Redux. It may solve your problem in a nice and effortless manner.

Check out the following live-snippet, paying attention that intermediate component is not getting re-rendered as you type:

const { useEffect } = React,
      { render } = ReactDOM,
      { createStore } = Redux,
      { Provider, useSelector, useDispatch } = ReactRedux

const defaultState = {data:''},
      appReducer = (state=defaultState, action) => {
        switch(action.type){
          case 'SET_DATA': {
            return {...state, data: action.payload}
          }
          default: return state
        }
      },
      store = createStore(appReducer)

const Parent = ({children}) => {
  const data = useSelector(({data}) => data)
  useEffect(() => console.log('Parent is rendered'))
  return (
    <div>
      <div>Current data value is: {data}</div>
      {children}
    </div>
  )
}

const Intermediate = ({children}) => {
  useEffect(() => console.log('Intermediate is rendered'))
  return (
    <div>{children}</div>
  )
}

const Child = () => {
  const dispatch = useDispatch()
  useEffect(() => console.log('Child is rendered'))
  return (
    <input
        onKeyUp={({target:{value}}) => dispatch({
          type: 'SET_DATA',
          payload: value
        })}
    />
  )
}

render (
  <Provider {...{store}} >
    <Parent>
      <Intermediate>
        <Child />
      </Intermediate>
    </Parent>
  </Provider>,
  document.getElementById('root')
)

<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script><script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script><script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.4/redux.min.js"></script><script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.1.1/react-redux.min.js"></script><div id="root"></div>


来源: stackexchange

问:
Changing React Theme Context on button click
Main.js

```<code>import React from "react"
//import PropTypes from "prop-types"
import ThemeContext from "./ThemeContext"

function Button(props) {
    return (
        <ThemeContext.Consumer>
            {theme => (
                <button className={`${theme}-theme`}>Switch Theme</button>
            )}
        </ThemeContext.Consumer>
    )
}

export default Button
</code>```

index.js

```<code>import ReactDOM from 'react-dom';
import App from './App';
import ThemeContext from "./ThemeContext"

ReactDOM.render(
    <ThemeContext.Provider value={"dark"}>
       <App />
    </ThemeContext.Provider>,
    document.getElementById('root'));
</code>```

Hello all, I am trying to get a handle on using Contexts with React. I have the code above that I am trying to do a basic change of the theme from light to dark.
Right now, I can manually change the theme of my page if I change the 'dark' to 'light', but I just want to be able to do this by clicking the button. It has been very frustrating today to try to get to work and I have googled a lot but everything that I found was a little more complex and I guess I was unable to understand. Any help would be appreciated. Thank you

答:
How about passing down a callback to change the theme along with your theme data in the context? Something like:</p>

```<code>// Wraps the previous theme provider render
class Root extends Component {
  // Store theme in state
  state = {
    theme: "dark"
  };

  // Callback to change it
  changeTheme = newTheme => {
    this.setState({ theme: newTheme });
  };

  render() {
    const { theme } = this.state;
    // Here pass down an object instead of a string with both the theme string and the callback
    return (
      <ThemeContext.Provider value={{ theme: theme, changeTheme: this.changeTheme }}>
        <App />
      </ThemeContext.Provider>
    );
  }
}

function Button(props) {
  return (
    // your consumer now gets both the theme and the callback
    <ThemeContext.Consumer>
      {({ theme, changeTheme }) => (
        <button
          onClick={() => changeTheme(theme === "dark" ? "light" : "dark")}
          className={`${theme}-theme`}
        >
          Switch Theme
        </button>
      )}
    </ThemeContext.Consumer>
  );
}

// Finally just render the root
ReactDOM.render(<Root />, document.getElementById("root"));
</code>```

ContentLicense: CC BY-SA 4.0

Body:
Main.js

import React from "react"
//import PropTypes from "prop-types"
import ThemeContext from "./ThemeContext"

function Button(props) {
    return (
        <ThemeContext.Consumer>
            {theme => (
                <button className={`${theme}-theme`}>Switch Theme</button>
            )}
        </ThemeContext.Consumer>
    )
}

export default Button

index.js

import ReactDOM from 'react-dom';
import App from './App';
import ThemeContext from "./ThemeContext"

ReactDOM.render(
    <ThemeContext.Provider value={"dark"}>
       <App />
    </ThemeContext.Provider>,
    document.getElementById('root'));

Hello all, I am trying to get a handle on using Contexts with React. I have the code above that I am trying to do a basic change of the theme from light to dark.
Right now, I can manually change the theme of my page if I change the 'dark' to 'light', but I just want to be able to do this by clicking the button. It has been very frustrating today to try to get to work and I have googled a lot but everything that I found was a little more complex and I guess I was unable to understand. Any help would be appreciated. Thank you

Body:
How about passing down a callback to change the theme along with your theme data in the context? Something like:

// Wraps the previous theme provider render
class Root extends Component {
  // Store theme in state
  state = {
    theme: "dark"
  };

  // Callback to change it
  changeTheme = newTheme => {
    this.setState({ theme: newTheme });
  };

  render() {
    const { theme } = this.state;
    // Here pass down an object instead of a string with both the theme string and the callback
    return (
      <ThemeContext.Provider value={{ theme: theme, changeTheme: this.changeTheme }}>
        <App />
      </ThemeContext.Provider>
    );
  }
}

function Button(props) {
  return (
    // your consumer now gets both the theme and the callback
    <ThemeContext.Consumer>
      {({ theme, changeTheme }) => (
        <button
          onClick={() => changeTheme(theme === "dark" ? "light" : "dark")}
          className={`${theme}-theme`}
        >
          Switch Theme
        </button>
      )}
    </ThemeContext.Consumer>
  );
}

// Finally just render the root
ReactDOM.render(<Root />, document.getElementById("root"));


问:
Sum columns from two relatable tables and group by another column (postgresql)
Given two tables:

teachers: ID, school_id

schools:  ID, student_population, district.

...what query can sum the number of teachers and students by district?

sample data:

```<code>Teachers
ID, school_id
1, 1
2, 1
3, 2
4, 3

Schools
ID, student_population, district
1, 45, Falaba
2, 23, Falaba
3, 87, Bonth
4, 10, Moyamba
</code>```

Desired results:

```<code>teachers, students, district
3, 68, Falaba
1, 87, Bonth
0, 10, Moyamba
</code>```

My first try was:

```<code>select count(*) as teachers, sum(student_population), district from teachers join schools on teachers.school_id = schools.id group by district.
</code>```

...however, this query results in each school's student_population being factored for each teacher who belongs to it. Consequently, the total student population for Falaba results to 113 (45+45+23) instead of 68.

答:
Assuming that table teachers has (at least) a second column that contains the id of the teacher, you can do:

```<code>select
    count(distinct t.teacher_id) teachers
    sum(s.student_population) students,
    s.district
from schools s
inner join teachers t on t.school_id = s.id
group by s.district
</code>```

A better option is to pre-aggregate the teachers table:

```<code>select
    sum(t.teachers) teachers,
    sum(s.student_population) students,
    s.district
from schools s
inner join (select school_id, count(*) teachers from teachers group by school_id) t
    on t.school_id = s.id
group by s.district
</code>```

Demo on DB Fiddle:

```
teachers | students | district
-------: | -------: | :-------
       1 |       87 | Bonth
       3 |       68 | Falaba
```

Body:
Given two tables:

teachers: ID, school_id

schools:  ID, student_population, district.

...what query can sum the number of teachers and students by district?

sample data:

Teachers
ID, school_id
1, 1
2, 1
3, 2
4, 3

Schools
ID, student_population, district
1, 45, Falaba
2, 23, Falaba
3, 87, Bonth
4, 10, Moyamba

Desired results:

teachers, students, district
3, 68, Falaba
1, 87, Bonth
0, 10, Moyamba

My first try was:

select count(*) as teachers, sum(student_population), district from teachers join schools on teachers.school_id = schools.id group by district.

...however, this query results in each school's student_population being factored for each teacher who belongs to it. Consequently, the total student population for Falaba results to 113 (45+45+23) instead of 68.

Body:
Assuming that table teachers has (at least) a second column that contains the id of the teacher, you can do:

select
    count(distinct t.teacher_id) teachers
    sum(s.student_population) students,
    s.district
from schools s
inner join teachers t on t.school_id = s.id
group by s.district

A better option is to pre-aggregate the teachers table:

select
    sum(t.teachers) teachers,
    sum(s.student_population) students,
    s.district
from schools s
inner join (select school_id, count(*) teachers from teachers group by school_id) t
    on t.school_id = s.id
group by s.district

Demo on DB Fiddle:

teachers | students | district
-------: | -------: | :-------
       1 |       87 | Bonth
       3 |       68 | Falaba


问:
Service worker fetching static assets for multilingual site
I've got static site (generated with Pelican) with a multilingual structure, e.g.

```<code>www.example.com/
www.example.com/index.html
www.example.com/page1.html
www.example.com/es/
www.example.com/es/index.html
www.example.com/es/page1.html
</code>```

I've cached the JS and CSS and the index files with a service worker install event:

```<code>const staticCacheName = 'static-cache-v5';

const filesToCache = [
  '/',
  '/index.html',
  '/es/index.html',
  '/offline.html',
  'static/js/main..js',
  'static/css/styles.css',
]

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(staticCacheName).then((cache) => {
      return cache.addAll(filesToCache);
    })
  );

  self.skipWaiting();
});
</code>```

and I'm using a cache, falling back to network strategy:

```<code>self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request).then(function(response) {
      return response || fetch(event.request);
    })
  );
});
</code>```

The issue I have is when the www.example.com/es/index.html or es/offline.html  is accessed offline and loading the CSS and JS files. The problem is that since the es/index.html files references the CSS and JS as ../static/css/styles.css and ../static/js/main.js, they can't find the files in the cache. I've tried to find a way to alter the request and response but so far I've failed. Any help?

答:
Well, you can write some logic in your code where the caches.match(event.request) is changed to something like caches.match(event.request) || caches.match(*canonical-url*) (in pseudo-code). You have possibly had a bug in your code if you tried this already. Another option would be to cache the files twice – with their root-relative paths and their canonical "../" paths. This of course isn't optimal since cache is used twice.

I think the best option would be to generate your site so that it always uses root-relative static asset paths. Replace all "../static/bla" with "/static/bla" and everything should work out of the box very neatly :)

Body:
I've got static site (generated with Pelican) with a multilingual structure, e.g.

www.example.com/
www.example.com/index.html
www.example.com/page1.html
www.example.com/es/
www.example.com/es/index.html
www.example.com/es/page1.html

I've cached the JS and CSS and the index files with a service worker install event:

const staticCacheName = 'static-cache-v5';

const filesToCache = [
  '/',
  '/index.html',
  '/es/index.html',
  '/offline.html',
  'static/js/main..js',
  'static/css/styles.css',
]

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(staticCacheName).then((cache) => {
      return cache.addAll(filesToCache);
    })
  );

  self.skipWaiting();
});

and I'm using a cache, falling back to network strategy:

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request).then(function(response) {
      return response || fetch(event.request);
    })
  );
});

The issue I have is when the www.example.com/es/index.html or es/offline.html  is accessed offline and loading the CSS and JS files. The problem is that since the es/index.html files references the CSS and JS as ../static/css/styles.css and ../static/js/main.js, they can't find the files in the cache. I've tried to find a way to alter the request and response but so far I've failed. Any help?


问:
Postgresql client authentication issue
I am struggling with the postgresql's access control file pg_hba.conf... it's never happy, and all I want to do is straight forward:
A) Allow access to ALL from localhost
B) Allow access to ALL from 10.8.0.* (VPN)
C) Deny ALL remaining

I've read the wiki page on the pgsql's official website, but can't figure out what's wrong with my configuration; I connect to the VPN (which works nice) and then attempt to connect to pgsql using pgadmin => fails; I also try to install a simple punBB forum (on the same machine as the database server) and I get can't connect to database... It's all configuration issue...

Here's a sample of my current permissions:

```<code>host    all     all     10.8.0.0/24     md5
local   all         postgres                          ident
local   all         all                               ident
host    all         all         127.0.0.1/32          trust
</code>```

Any ideas?

答:
I have no idea which "wiki page on the pgsql's official website" have you read but the manual is quite nice and has examples:

```<code># Allow any user on the local system to connect to any database with
# any database user name using Unix-domain sockets (the default for local
# connections).
#
# TYPE  DATABASE        USER            CIDR-ADDRESS            METHOD
local   all             all                                     trust

# The same using local loopback TCP/IP connections.
#
# TYPE  DATABASE        USER            CIDR-ADDRESS            METHOD
host    all             all             127.0.0.1/32            trust

# Allow any user from 10.8.0.0/24 to connect to all
# databases if the user's password is correctly supplied.
#
# TYPE  DATABASE        USER            CIDR-ADDRESS            METHOD
host    all             all             10.8.0.0/24             md5
</code>```

And don't forget to reload the server after the changes.

ContentLicense: CC BY-SA 3.0

Title: Postgresql client authentication issue

Body:
I am struggling with the postgresql's access control file pg_hba.conf... it's never happy, and all I want to do is straight forward:
A) Allow access to ALL from localhost
B) Allow access to ALL from 10.8.0.* (VPN)
C) Deny ALL remaining

I've read the wiki page on the pgsql's official website, but can't figure out what's wrong with my configuration; I connect to the VPN (which works nice) and then attempt to connect to pgsql using pgadmin => fails; I also try to install a simple punBB forum (on the same machine as the database server) and I get can't connect to database... It's all configuration issue...

Here's a sample of my current permissions:

host    all     all     10.8.0.0/24     md5
local   all         postgres                          ident
local   all         all                               ident
host    all         all         127.0.0.1/32          trust

Any ideas?

Body:
I have no idea which "wiki page on the pgsql's official website" have you read but the manual is quite nice and has examples:

# Allow any user on the local system to connect to any database with
# any database user name using Unix-domain sockets (the default for local
# connections).
#
# TYPE  DATABASE        USER            CIDR-ADDRESS            METHOD
local   all             all                                     trust

# The same using local loopback TCP/IP connections.
#
# TYPE  DATABASE        USER            CIDR-ADDRESS            METHOD
host    all             all             127.0.0.1/32            trust

# Allow any user from 10.8.0.0/24 to connect to all
# databases if the user's password is correctly supplied.
#
# TYPE  DATABASE        USER            CIDR-ADDRESS            METHOD
host    all             all             10.8.0.0/24             md5

And don't forget to reload the server after the changes.


问:
Expanding reference range of formulas which operate on a "database" when more items (rows, columns) are added to the database (tricks?, no VBA)
I included possible solutions to this problem below, however I'm hoping that perhaps somebody knows other ways and/or some neat tricks to achieve this.

1) Say we have a simple "database" in excel (as in the screenshot below).

2) Say we have formulas which operate on this entire range, like for example the VLOOKUP function in the screenshot.

3) Now obviously, if we added more rows to this "database" the existing VLOOKUP function will NOT include them - it will still operate only on the previously declared range.

Possible solutions:

1) One could obviously solve this problem with a VBA macro, however I would like to consider solving this with just the Excel formulas/features

2) One could use the range for the entire sheet in the original VLOOKUP i.e. $B$2:$D$1048576 and include a function not to take blank cells into consideration

Do you know any other solutions or neat tricks?

Thank you in Advance!

Danny

答: Convert your range to table and refer to table ranges in formula.


问:
Is Byte Really The Minimum Addressable Unit?
Section 3.6 of C11 standard defines "byte" as "addressable unit of data storage ... to hold ... character".

Section 1.7 of C++11 standard defines "byte" as "the fundamental storage unit in the C++ memory model ... to contain ... character".

Both definitions does not say that "byte" is the minimum addressable unit. Is this because standards intentionally want to abstract from a specific machine ? Can you provide a real example of machine where C/C++ compiler were decided to have "byte" longer/shorter than the minimum addressable unit ?

答:
(Thank you everyone who commented and answered, every word helps)

Memory model of a programming language and memory model of the target machine are different things.

Yes, byte is the minimum addressable unit in context of memory model of programming language.

No, byte is not the minimum addressable unit in context of memory model of machine. For example, there are machines where minimum addressable unit is longer or shorter than the "byte" of programming language:

longer: HP Saturn   - 4-bit unit vs 8-bit byte gcc (thanks Nate).

shorter: IBM 360    - 36-bit unit vs 6-bit byte (thanks Antti)

longer: Intel 8051  - 1-bit unit vs 8-bit byte (thanks Busybee)

longer: Ti TMS34010 - 1-bit unit vs 8-bit byte (thanks Wcochran)


问:
Inability to write in mongoDB: Inability to write in mongoDB:
Hi,when I try to save in the mongoDB no data is saved

I put more code in my app to better report the bug. The question is: In the code that I created to be able to record in the DB, why doesn't it work? What am I doing wrong?

My model is:

```<code>const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const pacientesSchema = new Schema({
    nombre: {
        type: String,
        trim: true,
    },
    propietario: {
        type: String,
        trim: true
    },
    fecha: {
        type: String,
        trim: true
    },
    telefono: {
        type: String,
        trim: true
    },
    hora: {
        type: String,
        trim: true
    },
    sintomas: {
        type: String,
        trim: true
    }
});

module.exports = mongoose.model('Paciente', pacientesSchema);
</code>```

My controller:

```<code>>     exports.nuevoCliente = async (req, res, next) => {
>         // console.log(req.body);
>
>         // Crear Objeto de paciente con datos de req.body
>         const paciente = new Paciente(req.body);
>         try {
>             await paciente.save();
>             res.json({ mensaje : 'El cliente se agregó correctamente'});
>             // console.log(paciente);
>
>         } catch (error) {
>             console.log(error);
>             next();
>         }
>     }
</code>```

With the kind suggestions of Stennie and Kris I made this change, it doesn't work, what else could I try? what am I missing ???

```<code>exports.nuevoCliente = async (req, res, next) => {
    // console.log(req.body);

    // Crear Objeto de paciente con datos de req.body
    const paciente = new Paciente(req.body);

    try {
        await paciente.save({
            nombre: req.body.nombre,
            propietario: req.body.propietario,
            fecha: req.body.fecha,
            telefono: req.body.telefono,
            hora: req.body.hora,
            sintomas: req.body.sintomas
        });
        res.json({ mensaje : 'El cliente se agregó correctamente'});
        // console.log(paciente);

    } catch (error) {
        console.log(error);
        next();
    }
}
</code>```

My main index:

```<code>const express = require('express');
const mongoose = require('mongoose');
const routes = require('./routes');
const bodyParser = require('body-parser');

// Crear el servidor
const app = express();

// Conectar con MongoDB
mongoose.Promise = global.Promise;
mongoose.connect('mongodb://localhost/veterinaria', {
    useNewUrlParser: true,
    useUnifiedTopology: true,
    useFindAndModify: false
});

// Habilitar el body-parser
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));

// Habilitar Routing
app.use('/', routes())

// Puerto y Arrancar
app.listen(4000, () => {
    console.log('Servidor funcionando')
})
</code>```

Thanks everybody

EDIT: Hello everyone, I already have the solution, it was a link failure when connecting compass with Atlas.
The link I used allowed me to connect and create DB and collections, but not to put data in the collection. This was the link that compass offered me:

```<code>mongodb+srv://<username>:<password>@cluster0-srtud.mongodb.net/test
</code>```

and this is the correct code:

```<code>mongodb://localhost:27017/?readPreference=primary&appname=MongoDB%20Compass&ssl=false
</code>```

It was a beginner's failure not to know that it was not the right link

Thanks to everybody

答:
If you only want to add one entry to an existing database, you can do so with

```<code>db.COLLECTION_NAME.insert({})
</code>```

If you don't know how to add a database or a collection you can find some useful examples here: https://www.tutorialspoint.com/mongodb/mongodb_insert_document.htm

EDIT:
You need to import your model in your controller first

const Pacientes = require('../models/Pacientes.js');
```

Body:
Hi,when I try to save in the mongoDB no data is saved

I put more code in my app to better report the bug. The question is: In the code that I created to be able to record in the DB, why doesn't it work? What am I doing wrong?

My model is:

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const pacientesSchema = new Schema({
    nombre: {
        type: String,
        trim: true,
    },
    propietario: {
        type: String,
        trim: true
    },
    fecha: {
        type: String,
        trim: true
    },
    telefono: {
        type: String,
        trim: true
    },
    hora: {
        type: String,
        trim: true
    },
    sintomas: {
        type: String,
        trim: true
    }
});

module.exports = mongoose.model('Paciente', pacientesSchema);

My controller:

>     exports.nuevoCliente = async (req, res, next) => {
>         // console.log(req.body);
>
>         // Crear Objeto de paciente con datos de req.body
>         const paciente = new Paciente(req.body);
>         try {
>             await paciente.save();
>             res.json({ mensaje : 'El cliente se agregó correctamente'});
>             // console.log(paciente);
>
>         } catch (error) {
>             console.log(error);
>             next();
>         }
>     }

With the kind suggestions of Stennie and Kris I made this change, it doesn't work, what else could I try? what am I missing ???

exports.nuevoCliente = async (req, res, next) => {
    // console.log(req.body);

    // Crear Objeto de paciente con datos de req.body
    const paciente = new Paciente(req.body);

    try {
        await paciente.save({
            nombre: req.body.nombre,
            propietario: req.body.propietario,
            fecha: req.body.fecha,
            telefono: req.body.telefono,
            hora: req.body.hora,
            sintomas: req.body.sintomas
        });
        res.json({ mensaje : 'El cliente se agregó correctamente'});
        // console.log(paciente);

    } catch (error) {
        console.log(error);
        next();
    }
}

My main index:

const express = require('express');
const mongoose = require('mongoose');
const routes = require('./routes');
const bodyParser = require('body-parser');

// Crear el servidor
const app = express();

// Conectar con MongoDB
mongoose.Promise = global.Promise;
mongoose.connect('mongodb://localhost/veterinaria', {
    useNewUrlParser: true,
    useUnifiedTopology: true,
    useFindAndModify: false
});

// Habilitar el body-parser
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));

// Habilitar Routing
app.use('/', routes())

// Puerto y Arrancar
app.listen(4000, () => {
    console.log('Servidor funcionando')
})

Thanks everybody

EDIT: Hello everyone, I already have the solution, it was a link failure when connecting compass with Atlas.
The link I used allowed me to connect and create DB and collections, but not to put data in the collection. This was the link that compass offered me:

mongodb+srv://<username>:<password>@cluster0-srtud.mongodb.net/test

and this is the correct code:

mongodb://localhost:27017/?readPreference=primary&appname=MongoDB%20Compass&ssl=false

It was a beginner's failure not to know that it was not the right link

Thanks to everybody

Body:
If you only want to add one entry to an existing database, you can do so with

db.COLLECTION_NAME.insert({})

If you don't know how to add a database or a collection you can find some useful examples here: https://www.tutorialspoint.com/mongodb/mongodb_insert_document.htm

EDIT:
You need to import your model in your controller first

const Pacientes = require('../models/Pacientes.js');


问:
Convert factor value into numeric in a column of dataframe
I have a data frame that has two string characters stored in each row

```<code>s   ['64.0', '2']
a   ['63.0', '2']
b   ['63.0', '1']
</code>```

How to convert the first character string into numeric value,and omit the second character string,which results into data frame as follows :

```<code>s    64.0
a    63.0
b    63.0
</code>```

答:
We could use parse_number

```<code>library(dplyr)
library(readr)
df2 <-  df1 %>%
          mutate(col2 = parse_number(as.character(col2)))
df2
#   col1 col2
#1    s   64
#2    a   63
#3    b   63
</code>```

Or using base R with sub

```<code>as.numeric( sub("\\D+([0-9.]+)[^0-9]+.*", "\\1", df1$col2))
</code>```

data

```<code>df1 <- structure(list(col1 = c("s", "a", "b"), col2 = structure(3:1, .Label = c("['63.0', '1']",
"['63.0', '2']", "['64.0', '2']"), class = "factor")), row.names = c(NA,
-3L), class = "data.frame")
</code>```

Body:
I have a data frame that has two string characters stored in each row

s   ['64.0', '2']
a   ['63.0', '2']
b   ['63.0', '1']

How to convert the first character string into numeric value,and omit the second character string,which results into data frame as follows :

s    64.0
a    63.0
b    63.0

Body:
We could use parse_number

library(dplyr)
library(readr)
df2 <-  df1 %>%
          mutate(col2 = parse_number(as.character(col2)))
df2
#   col1 col2
#1    s   64
#2    a   63
#3    b   63

Or using base R with sub

as.numeric( sub("\\D+([0-9.]+)[^0-9]+.*", "\\1", df1$col2))

data

df1 <- structure(list(col1 = c("s", "a", "b"), col2 = structure(3:1, .Label = c("['63.0', '1']",
"['63.0', '2']", "['64.0', '2']"), class = "factor")), row.names = c(NA,
-3L), class = "data.frame")


问:
Dynamically configure Http.BaseAddress for Client Side Blazor Deployment Environment
In this example, Hosting Blazor, the author has a Blazor ClientSide App that calls Azure Functions.  The author sets a Http.BaseAddress.  Any thoughts on the best way to configure the Client Side Blazor "Http.BaseAddress" for a local URL when
debugging and the Azure Functions URL when the Blazor app is deployed to Azure folders?

Debugging:

Http.BaseAddress = new Uri("https://localhost:12345");

Production:

Http.BaseAddress = new Uri("https://blazorapi.azurewebsites.net");

```<code>@functions {
Book[] books;
string message;
  protected override async Task OnInitAsync()
  {
    message = "OnInitAsync";
    Http.BaseAddress = new Uri("https://blazorapi.azurewebsites.net");
    books = await Http.GetJsonAsync<Book[]>("/api/BooksFunction");
    message = "downloaded books";
  }
}
</code>```

答:
Update because Blazor got more complete:

By now, Blazor actually has the config-process we're used to from other .NET Applications, just a litte more...frontend-y:

You create an appsettings.json file for special configurations, like appsettings.Release.json. For Blazor you have to put it into the wwwroot folder.

The file should look something like this:

```<code>{
  "BaseUrl": "https://localhost:12345"
}
</code>```

And in your appsettings.Release.json, you would put your prod url instead of localhost.
You can now go into your Program.cs and read the settings like this:

```<code>baseAddress = builder.Configuration.GetValue<string>("BaseUrl");
builder.Services.AddSingleton(new HttpClient
{
    BaseAddress = new Uri(baseAddress) }
);
</code>```

Now all your class constructed automatically, like components, can use DI to get the configured HttpClient. You just put this at the top:

```<code>@inject HttpClient Http
</code>```

And then use it from there. Of course use the DI scope of your choosing here (Transient/Scoped/Singleton).

Or, you know, just save the baseAddress somewhere if you don't wanna use DI.

<s>This comes with preview-5, but we're even further by now with RC-1</s>

Blazor is in production now, no need to play around with preview versions anymore.

Old answer:

As far as I know there isn't a "good" way of getting the environment yet, but since it's only about prod vs dev, you can do hte same as me and just use compiler variables old school style:

```<code>public class Program
{
    internal const string BaseAddress = "http://localhost:81/";
    internal const string ProdBaseAddress = "http://localhost:5001/";

    public static async Task Main(string[] args)
    {
        var builder = WebAssemblyHostBuilder.CreateDefault(args);
        builder.RootComponents.Add<App>("app");

        var host = builder.Build();
        var httpClient = host.Services.GetRequiredService<HttpClient>();
#if DEBUG
        httpClient.BaseAddress = new Uri(BaseAddress);
#else
        httpClient.BaseAddress = new Uri(ProdBaseAddress);
#endif

        Console.WriteLine($"Set BaseAddress: {BaseAddress}");
        await host.RunAsync();
    }
}
</code>```

Just make sure the DEBUG variable is actually set in your Debug build - mine was not.

Edit: Forgot the point: Locally you're likely using 'Debug' config, while when deploying you probably have a different config, like 'Release'.

Body:
In this example, Hosting Blazor, the author has a Blazor ClientSide App that calls Azure Functions.  The author sets a Http.BaseAddress.  Any thoughts on the best way to configure the Client Side Blazor "Http.BaseAddress" for a local URL when
debugging and the Azure Functions URL when the Blazor app is deployed to Azure folders?

Debugging:

Http.BaseAddress = new Uri("https://localhost:12345");

Production:

Http.BaseAddress = new Uri("https://blazorapi.azurewebsites.net");

@functions {
Book[] books;
string message;
  protected override async Task OnInitAsync()
  {
    message = "OnInitAsync";
    Http.BaseAddress = new Uri("https://blazorapi.azurewebsites.net");
    books = await Http.GetJsonAsync<Book[]>("/api/BooksFunction");
    message = "downloaded books";
  }
}

Body:
Update because Blazor got more complete:

By now, Blazor actually has the config-process we're used to from other .NET Applications, just a litte more...frontend-y:

You create an appsettings.json file for special configurations, like appsettings.Release.json. For Blazor you have to put it into the wwwroot folder.

The file should look something like this:

{
  "BaseUrl": "https://localhost:12345"
}

And in your appsettings.Release.json, you would put your prod url instead of localhost.
You can now go into your Program.cs and read the settings like this:

baseAddress = builder.Configuration.GetValue<string>("BaseUrl");
builder.Services.AddSingleton(new HttpClient
{
    BaseAddress = new Uri(baseAddress) }
);

Now all your class constructed automatically, like components, can use DI to get the configured HttpClient. You just put this at the top:

@inject HttpClient Http

And then use it from there. Of course use the DI scope of your choosing here (Transient/Scoped/Singleton).

Or, you know, just save the baseAddress somewhere if you don't wanna use DI.

<s>This comes with preview-5, but we're even further by now with RC-1</s>

Blazor is in production now, no need to play around with preview versions anymore.

Old answer:

As far as I know there isn't a "good" way of getting the environment yet, but since it's only about prod vs dev, you can do hte same as me and just use compiler variables old school style:

public class Program
{
    internal const string BaseAddress = "http://localhost:81/";
    internal const string ProdBaseAddress = "http://localhost:5001/";

    public static async Task Main(string[] args)
    {
        var builder = WebAssemblyHostBuilder.CreateDefault(args);
        builder.RootComponents.Add<App>("app");

        var host = builder.Build();
        var httpClient = host.Services.GetRequiredService<HttpClient>();
#if DEBUG
        httpClient.BaseAddress = new Uri(BaseAddress);
#else
        httpClient.BaseAddress = new Uri(ProdBaseAddress);
#endif

        Console.WriteLine($"Set BaseAddress: {BaseAddress}");
        await host.RunAsync();
    }
}

Just make sure the DEBUG variable is actually set in your Debug build - mine was not.

Edit: Forgot the point: Locally you're likely using 'Debug' config, while when deploying you probably have a different config, like 'Release'.


问:
Website With json sorting different array's with JavaScript
I am trying things out in javascript with my website where it is possible to stream multiple series with just one html file thanks to search querys and a json file with the information. but now i want to make a home site with the series sorted by the air date of the latest ep. But I've put everything in different array's named after the serie so i could easely access the serie's data with the search query. but i don't seem to find any way to sort those different array's with each other.

my json:

```<code>{
 "arifureta": [
        {
            "name": "arifureta",
            "trailer": "https://www.mp4upload.com/embed-9rlskzipxxaw.html",
            "latest_ep": 4,
            "episodes": {
                "1": {
                    "address": "https://www.mp4upload.com/embed-rnah6dqcym96.html",
                    "date": "8-7-2019"
                },
                "2": {
                    "address": " https://www.mp4upload.com/embed-y93t9mysnnun.html",
                    "date": "15-7-2019"
                }
            }
        }
    ],
    "boku_no_hero_academia": [
        {
            "name": "Boku no hero academia",
            "trailer": "trailer.mp4",
            "latest_ep": 4
            "episodes": {
                "1": {
                    "address": "ep1.mp4",
                    "date": "3-4-2019"
                },
                "2": {
                    "address": "ep2.mp4",
                    "date": "10-4-2019"
                }
            }
        }
    ]`
}
</code>```

I don't really have a usable javascript besides the basic .sort( (a, b) => {}), and i've tried a bunch of things but i can't seem to sort it.

Thanks in advance for the help.

答:
CodeSandbox DEMO

Since the data is an object then we need to use Object.entries, because objects can't be sorted. Object.entries return an array of key-value pairs, which can be simply sorted/filtered as you need.

function getEpisodes(entry) {
  return Object.values(entry[1][0].episodes);
}

function getCloserEpisodeDate(episodes) {
  return parseDate(
    episodes.sort((a, b) => parseDate(a.date) < parseDate(b.date))[0].date
  );
}

function getSortedEntries(data) {
  const entries = Object.entries(data);
  return entries.sort(
    (a, b) =>
      getCloserEpisodeDate(getEpisodes(a)) <
      getCloserEpisodeDate(getEpisodes(b))
  );
}
```

<p>Dates in <code>episodes</code> are not valid for <code>Date()</code> constructor, that's why we need to parse it and build a new Date object from it. <code>Date</code> is useful for comparison.</p>

<pre class="lang-js prettyprint-override"><code>function parseDate(date) {
  var [day, month, year] = date.split("-");
  return new Date(year, month - 1, day);
}
</code>```

Body:
I am trying things out in javascript with my website where it is possible to stream multiple series with just one html file thanks to search querys and a json file with the information. but now i want to make a home site with the series sorted by the air date of the latest ep. But I've put everything in different array's named after the serie so i could easely access the serie's data with the search query. but i don't seem to find any way to sort those different array's with each other.

my json:

{
 "arifureta": [
        {
            "name": "arifureta",
            "trailer": "https://www.mp4upload.com/embed-9rlskzipxxaw.html",
            "latest_ep": 4,
            "episodes": {
                "1": {
                    "address": "https://www.mp4upload.com/embed-rnah6dqcym96.html",
                    "date": "8-7-2019"
                },
                "2": {
                    "address": " https://www.mp4upload.com/embed-y93t9mysnnun.html",
                    "date": "15-7-2019"
                }
            }
        }
    ],
    "boku_no_hero_academia": [
        {
            "name": "Boku no hero academia",
            "trailer": "trailer.mp4",
            "latest_ep": 4
            "episodes": {
                "1": {
                    "address": "ep1.mp4",
                    "date": "3-4-2019"
                },
                "2": {
                    "address": "ep2.mp4",
                    "date": "10-4-2019"
                }
            }
        }
    ]`
}

I don't really have a usable javascript besides the basic .sort( (a, b) => {}), and i've tried a bunch of things but i can't seem to sort it.

Thanks in advance for the help.

Body:
CodeSandbox DEMO

Since the data is an object then we need to use Object.entries, because objects can't be sorted. Object.entries return an array of key-value pairs, which can be simply sorted/filtered as you need.

function getEpisodes(entry) {
  return Object.values(entry[1][0].episodes);
}

function getCloserEpisodeDate(episodes) {
  return parseDate(
    episodes.sort((a, b) => parseDate(a.date) < parseDate(b.date))[0].date
  );
}

function getSortedEntries(data) {
  const entries = Object.entries(data);
  return entries.sort(
    (a, b) =>
      getCloserEpisodeDate(getEpisodes(a)) <
      getCloserEpisodeDate(getEpisodes(b))
  );
}

Dates in episodes are not valid for Date() constructor, that's why we need to parse it and build a new Date object from it. Date is useful for comparison.

function parseDate(date) {
  var [day, month, year] = date.split("-");
  return new Date(year, month - 1, day);
}


问:
Binary Tree Python - AttributeError: 'NoneType' object has no attribute 'left'
I'm trying to add elements to a binary tree and print them in pre-order.

The elements that are added to the binary tree are of type node.

I'm getting an error while adding an element:
AttributeError: 'NoneType' object has no attribute 'left'

Please let me know where I have to make a change
Below is the code:

```<code>class Node(object):

    def __init__(self, item, left=None, right=None):
        self.item = item
        self.left = None
        self.right = None

    def __repr__(self):
        return '{}'.format(self.item)

class BinaryTree(object):

    def __init__(self, root=None):
        self.root = root

    def add(self, value):

        val = self.root
        if not val:
            val = value
        elif not val.left:
            val = value
        elif not val.right:
            val = value
        else:
            self.left = val.left.add(value)
        return val

    def preorder(self):
        val = self.root
        print(val)
        if val.left:
            val.left.preorder()
        if val.right:
            val.right.preorder()

def main():

    binary_tree = BinaryTree()

    print("Adding nodes in tree")
    for i in range(1, 11):
        node = Node(i)
        binary_tree.add(node)

    print("Printing preorder...")
    binary_tree.preorder()

if __name__ == '__main__':
    main()

</code>```

Error:

```<code>Adding nodes in tree
Printing preorder...
None
Traceback (most recent call last):
  File ".\binary_tree_test5.py", line 52, in <module>
    main()
  File ".\binary_tree_test5.py", line 49, in main
    binary_tree.preorder()
  File ".\binary_tree_test5.py", line 33, in preorder
    if val.left:
AttributeError: 'NoneType' object has no attribute 'left'
</code>```

答:
binary_tree = BinaryTree() - BinaryTree.__init__ has a default argument of None for the root parameter.  When you add a Node and check for the root, if it doesn't have one you should make one.

```<code>....
    def add(self, value):
        val = self.root
        if not val:
            self.root = value
            val = value
        ...
</code>```

Or

```<code>....
    def add(self, value):
        if not self.root:
            self.root = value
        val = self.root
        ...
</code>```

This will solve the problem of having a root of None as long as you call add on an empty tree before you do anything else.

If you want to maintain the option of creating empty trees, you might consider adding a meaningful Exception to methods that won't work for a rootless tree.

```<code>class RootLessException(Exception):
    pass
...
...
    def preorder(self):
        if not self.root:
            raise RootLessException
        val = self.root
        ...
</code>```

Body:
I'm trying to add elements to a binary tree and print them in pre-order.

The elements that are added to the binary tree are of type node.

I'm getting an error while adding an element:
AttributeError: 'NoneType' object has no attribute 'left'

Please let me know where I have to make a change
Below is the code:

class Node(object):

    def __init__(self, item, left=None, right=None):
        self.item = item
        self.left = None
        self.right = None

    def __repr__(self):
        return '{}'.format(self.item)

class BinaryTree(object):

    def __init__(self, root=None):
        self.root = root

    def add(self, value):

        val = self.root
        if not val:
            val = value
        elif not val.left:
            val = value
        elif not val.right:
            val = value
        else:
            self.left = val.left.add(value)
        return val

    def preorder(self):
        val = self.root
        print(val)
        if val.left:
            val.left.preorder()
        if val.right:
            val.right.preorder()

def main():

    binary_tree = BinaryTree()

    print("Adding nodes in tree")
    for i in range(1, 11):
        node = Node(i)
        binary_tree.add(node)

    print("Printing preorder...")
    binary_tree.preorder()

if __name__ == '__main__':
    main()

Error:

Adding nodes in tree
Printing preorder...
None
Traceback (most recent call last):
  File ".\binary_tree_test5.py", line 52, in <module>
    main()
  File ".\binary_tree_test5.py", line 49, in main
    binary_tree.preorder()
  File ".\binary_tree_test5.py", line 33, in preorder
    if val.left:
AttributeError: 'NoneType' object has no attribute 'left'

Body:
binary_tree = BinaryTree() - BinaryTree.__init__ has a default argument of None for the root parameter.  When you add a Node and check for the root, if it doesn't have one you should make one.

....
    def add(self, value):
        val = self.root
        if not val:
            self.root = value
            val = value
        ...

Or

....
    def add(self, value):
        if not self.root:
            self.root = value
        val = self.root
        ...

This will solve the problem of having a root of None as long as you call add on an empty tree before you do anything else.

If you want to maintain the option of creating empty trees, you might consider adding a meaningful Exception to methods that won't work for a rootless tree.

class RootLessException(Exception):
    pass
...
...
    def preorder(self):
        if not self.root:
            raise RootLessException
        val = self.root
        ...


问:
IDE for Python: test a script
Is there any IDE that allows to run a script in testing mode, allowing to replace at runtime, some values, like a folder or else?
I have a program that will have to run on a network i have no access to where I develop. Since it will use some specific folders to pick up files, I was wondering if i.e. I could use an IDE that using some parameters will translate all that is like \corporate\disk-c\myfolder into a c:\myfolder.

Thanks!

M

答: In absence of some other file based config, you could just keep the variable definitions in a a file that you import in the main script (e.g, config.py), then have two different versions of that file for 'on' and 'off' network, (or ' development' and 'production', whatever) with the appropriate settings.  No IDE needed.

Title: IDE for Python: test a script


问:
Angular html template as string with style attribute renders with NO style attribute
I am having a Util.ts which defines format function as shown below. The problem is on the small tag which has style property.

```<code>export const formatMessage = (message ) =>{
    return '<b>' + message.name+" </b><small style ='color:black;'>" +message.ts + '</small>  ' + message.c;
  }
</code>```

However when rendered small tag's style attribute is getting removed.

I am not sure why this behavior, The HTML string template returned by the formatMessage function is attached to the HTML using innerHTML of DIV as shown here.

```<code><ul style="list-style-type: none;">
  <li  *ngFor="let each of messages"><div class='messageStyle' [innerHTML]="each"> </div></li>
</ul>
</code>```

Why is this style property getting removed (while class property stays) and how do I address the issue?

答:
dom sanitizer stips the style from your html. it is done to prevent xss attacks. you can bypass security checks by doing this:

```<code>  constructor(private s: DomSanitizer) { }
...
  export const formatMessage = (message, sanitizer ) =>{
    return sanitizer.bypassSecurityTrustHtml('<b>' + message.name+" </b><small style ='color:black;'>" +message.ts + '</small>  ' + message.c);
  }
</code>```

and pass sanitizer to formatMessage

Body:
I am having a Util.ts which defines format function as shown below. The problem is on the small tag which has style property.

export const formatMessage = (message ) =>{
    return '' + message.name+" " +message.ts + '  ' + message.c;
  }

However when rendered small tag's style attribute is getting removed.

I am not sure why this behavior, The HTML string template returned by the formatMessage function is attached to the HTML using innerHTML of DIV as shown here.

Why is this style property getting removed (while class property stays) and how do I address the issue?

Body:
dom sanitizer stips the style from your html. it is done to prevent xss attacks. you can bypass security checks by doing this:

  constructor(private s: DomSanitizer) { }
...
  export const formatMessage = (message, sanitizer ) =>{
    return sanitizer.bypassSecurityTrustHtml('<b>' + message.name+" </b><small style ='color:black;'>" +message.ts + '</small>  ' + message.c);
  }

and pass sanitizer to formatMessage


问:
Email expiration tokens without usage of database and crontab deletion
I have API server with Auth (registration, login, forgotten password, etc..) based on JWT token session.

When user forgot password, he gets email with unique token and link where he can reset his password.

At this moment, I am generating UUID token which is saved into database with expiration field.

After user reset his password or token expires, this token is invalidated. Invalidated tokens are deleted every midnight by crontab to keep database clean.

Is there any other way to do this? Maybe without usage of database?

I was thinking about bundling token UUID into JWT string. This way I do not need database row.
But then I realized, that this token will be valid until it expires, so user can change his password infinitely. Only fix I see is add this token into revoked list (in database) until it expires, but then I again used database :D

Any ideas?

答:
I found answer in this article:

Create JWT token which is encrypted by secret made from current user's password hash + time of last password change. This way, token is one-time-use, because after user changes the password, next time someone tries to use this token again, token will not get decrypted correctly (not encrypted by same secret). In addition, if new password is same as old, token will still not be usable, because of additional timestamp information.

Another solution offered by @Horatiu Jeflea is to also use user's time of last password change to our advantage. Just ignore password change requests if token was generated before last change. In this solution is (I personally think) small chance that two password changes take place at same time what can mess this up, so I will use the first solution.


问:
Why does substr() return an empty string?
I don't know if I have a logical error, but my substr() function is keep returning an empty string? My initial thought was that I am cutting the string wrong, however even with a lower starting value, I am getting null string in my dataframe column.

I have looked at this PHP question to get some information, but didn't work: PHP: substr returns empty string

Reproducible example-

#Original Data set str() output
#'data.frame':  9245 obs. of  3 variables:
#$ Latitude   : num  29.7 29.7 29.7 29.6 29.7 ...
#$ Longitude  : num  -82.3 -82.4 -82.3 -82.4 -82.3 ...
#$ Census Code: chr  "120010011003032" "120010010004035" "120010002003009" "120010015213000" ...

#For example, even if I do this:
base::substr("120010011003032", 6, 1)

#Output : ""
#Desired output: 001100
```

I needed to cut census codes to generate tract information, and the tract information is usually first two being the state, next three the county, and the following six the tract.

答:
You need base::substr("120010011003032", 1, 6) ! (EDIT: or 11, 6 per your comment)

The arguments are start, stop not length, start; see the doc or type ?base::substr. Tip: always triple-check the R doc first. And also try copy-pasting the working examples it gives you, then see if/how they differ from yours. Or just try various argument values.

Body:
I don't know if I have a logical error, but my substr() function is keep returning an empty string? My initial thought was that I am cutting the string wrong, however even with a lower starting value, I am getting null string in my dataframe column.

I have looked at this PHP question to get some information, but didn't work: PHP: substr returns empty string

Reproducible example-

#Original Data set str() output
#'data.frame':  9245 obs. of  3 variables:
#$ Latitude   : num  29.7 29.7 29.7 29.6 29.7 ...
#$ Longitude  : num  -82.3 -82.4 -82.3 -82.4 -82.3 ...
#$ Census Code: chr  "120010011003032" "120010010004035" "120010002003009" "120010015213000" ...

#For example, even if I do this:
base::substr("120010011003032", 6, 1)

#Output : ""
#Desired output: 001100

I needed to cut census codes to generate tract information, and the tract information is usually first two being the state, next three the county, and the following six the tract.


Title: Why does substr() return an empty string?

Body:
base::substr("120010011003032", 6, 11)

"001100"


问:
Cell selection style changing on second tap
In my table view I am setting the the selection style inside

```<code>- (void)tableView:(UITableView *)iTableView didSelectRowAtIndexPath:(NSIndexPath *)iIndexPath {

MyCell *aCell = (MyCell *)[iTableView cellForRowAtIndexPath:iIndexPath];
aCell.selectionStyle = UITableViewCellSelectionStyleBlue;
</code>```

Now, the selection style changes on the second tap and not on the first tap. Once a cell is tapped then it works fine if you come back and select it again. What is the reason for this?

答: I guess the reason for this is that the tableView:didSelectRowAtIndexPath: method gets called when the cell have already been selected (surprise!). So the default selection style is applied before the method gets called first time, i.e. before you do your aCell.selectionStyle = UITableViewCellSelectionStyleBlue. When the selection style was changed once, apparently it remains for subsequent calls (taps). To fix this, you have to set the selection style in tableView:cellForRowAtIndexPath: or tableView:willSelectRowAtIndexPath: methods, which are called before selecting the cell.

Body:
In my table view I am setting the the selection style inside

- (void)tableView:(UITableView *)iTableView didSelectRowAtIndexPath:(NSIndexPath *)iIndexPath {

MyCell *aCell = (MyCell *)[iTableView cellForRowAtIndexPath:iIndexPath];
aCell.selectionStyle = UITableViewCellSelectionStyleBlue;

Now, the selection style changes on the second tap and not on the first tap. Once a cell is tapped then it works fine if you come back and select it again. What is the reason for this?


问:
how can I test scope with rspec
These are some code of my Cashout model.I can test all model with rspec but I don't know how can I test these scopes.

cashout.rb

```<code>class Cashout < ActiveRecord::Base

belongs_to :partner

scope :add_virtual_columns, select(
    "cashouts.*,
    ( SELECT SUM(c.amount) FROM cashouts c WHERE c.partner_id = cashouts.partner_id) as total_paid_amount,
    (
      (
      CASE
        WHEN (SELECT partner_type FROM partners WHERE cashouts.partner_id = partners.id) = 'administrator'
        THEN
          (
            CASE
                WHEN ( SELECT SUM(cr.partner_profit) FROM contact_records cr WHERE cr.partner_id in (SELECT id FROM partners WHERE company_id in (SELECT company_id FROM partners WHERE id = cashouts.partner_id))) IS NULL
                THEN 0
                ELSE ( SELECT SUM(cr.partner_profit + cr.company_profit) FROM contact_records cr WHERE cr.partner_id in (SELECT id FROM partners WHERE company_id in (SELECT company_id FROM partners WHERE id = cashouts.partner_id)))
            END
            )
        ELSE
          (
          CASE
            WHEN ( SELECT SUM(cr.partner_profit) FROM contact_records cr WHERE cr.partner_id = cashouts.partner_id) IS NULL
            THEN 0
            ELSE ( SELECT SUM(cr.partner_profit) FROM contact_records cr WHERE cr.partner_id = cashouts.partner_id)
          END
          )
      END
      )
      -
      ( SELECT SUM(c.amount) FROM cashouts c WHERE c.partner_id = cashouts.partner_id)
    ) as unpaid_amount"
  ).group('cashouts.id')
  scope :sort_by_total_paid_amount_asc, order("total_paid_amount ASC")
  scope :sort_by_total_paid_amount_desc, order("total_paid_amount DESC")
  scope :sort_by_unpaid_amount_asc, order("unpaid_amount ASC")
  scope :sort_by_unpaid_amount_desc, order("unpaid_amount DESC")
end
</code>```

Do you know how can I test these scopes with rspec and factorygirl?

答:
Guessing roughly at your schema, you first have to set up factories for all the pieces and their associations. Here's a rough outline. You'll have to fill in their other attributes with valid values.

Faker is extremely useful for filling in valid data.

```<code>factory :company do
end

factory :partner do
  company
end

factory :contact_record do
  partner
end

factory :cashout do
  partner
  total_paid_amount { Faker::Number.digit }
end
</code>```

Testing the sorting scopes are easy. Make an Array of cashouts with different amounts, sort them as you expect, and see if you get that back.

Our factories are already set up to give us cashouts with random total_paid_amounts. We just need to create a list of them.

```<code>context 'with cashouts' do
  let(:cashouts) {
    create_list(:cashout, 3)
  }

  describe '.sort_by_total_paid_amount_asc' do
    it 'sorts by total_paid_amount in ascending order' do
      expect(
        Cashout.sort_by_total_paid_amount_asc.to_a
      ).to eq cashouts.sort_by(&:total_amount_paid)
    end
  end

  describe '.sort_by_total_paid_amount_desc' do
    it 'sorts by total_paid_amount in descending order' do
      expect(
        Cashout.sort_by_total_paid_amount_desc.to_a
      ).to eq cashouts.sort_by(&:total_amount_paid).reverse
    end
  end
end
</code>```

I avoided generating the cashouts in order. This would put them in the table already in order and their default sorting might match our expectations.

Though I question the value of such literally named and trivial scopes. They're easily written as Cashout.order(total_paid_amount: :asc) which requires no testing.

Testing add_virtual_columns... add_virtual_columns is a poor name. It seems like it's adding a single column, unpaid_amount. I'd call it with_unpaid_amount.

with_unpaid_amount is more complicated because it's pretty complicated and requires more test data. Fortunately we have our relationships set up in our factories.

First, we set up our objects so they all share the same partner. There's several ways to do this, but I've chosen to generate the partner and pass it around. This makes it easier to modify each object to test different scenarios.

```<code>describe '.with_unpaid_amount' do
  let(:partner) {
    create(:partner)
  }
  let(:company) {
    create(:company, partner: partner)
  }
  let(:cashout) {
    create(:cashout, partner: partner)
  }
  let(:contact_record) {
    create(:contact_record, partner: partner)
  }
</code>```

With this in place you can now alter the objects to test different scenarios. For example, what if a partner is an administrator?

```<code>  context 'when the partner is an administrator' do
    before {
      partner.update!(partner_type: 'administrator')
    }

    it '...'
  end
</code>```

And so on from there.

Title: how can I test scope with rspec

Body:
These are some code of my Cashout model.I can test all model with rspec but I don't know how can I test these scopes.

cashout.rb

class Cashout < ActiveRecord::Base

belongs_to :partner

scope :add_virtual_columns, select(
    "cashouts.*,
    ( SELECT SUM(c.amount) FROM cashouts c WHERE c.partner_id = cashouts.partner_id) as total_paid_amount,
    (
      (
      CASE
        WHEN (SELECT partner_type FROM partners WHERE cashouts.partner_id = partners.id) = 'administrator'
        THEN
          (
            CASE
                WHEN ( SELECT SUM(cr.partner_profit) FROM contact_records cr WHERE cr.partner_id in (SELECT id FROM partners WHERE company_id in (SELECT company_id FROM partners WHERE id = cashouts.partner_id))) IS NULL
                THEN 0
                ELSE ( SELECT SUM(cr.partner_profit + cr.company_profit) FROM contact_records cr WHERE cr.partner_id in (SELECT id FROM partners WHERE company_id in (SELECT company_id FROM partners WHERE id = cashouts.partner_id)))
            END
            )
        ELSE
          (
          CASE
            WHEN ( SELECT SUM(cr.partner_profit) FROM contact_records cr WHERE cr.partner_id = cashouts.partner_id) IS NULL
            THEN 0
            ELSE ( SELECT SUM(cr.partner_profit) FROM contact_records cr WHERE cr.partner_id = cashouts.partner_id)
          END
          )
      END
      )
      -
      ( SELECT SUM(c.amount) FROM cashouts c WHERE c.partner_id = cashouts.partner_id)
    ) as unpaid_amount"
  ).group('cashouts.id')
  scope :sort_by_total_paid_amount_asc, order("total_paid_amount ASC")
  scope :sort_by_total_paid_amount_desc, order("total_paid_amount DESC")
  scope :sort_by_unpaid_amount_asc, order("unpaid_amount ASC")
  scope :sort_by_unpaid_amount_desc, order("unpaid_amount DESC")
end

Do you know how can I test these scopes with rspec and factorygirl?

Body:
Guessing roughly at your schema, you first have to set up factories for all the pieces and their associations. Here's a rough outline. You'll have to fill in their other attributes with valid values.

Faker is extremely useful for filling in valid data.

factory :company do
end

factory :partner do
  company
end

factory :contact_record do
  partner
end

factory :cashout do
  partner
  total_paid_amount { Faker::Number.digit }
end

Testing the sorting scopes are easy. Make an Array of cashouts with different amounts, sort them as you expect, and see if you get that back.

Our factories are already set up to give us cashouts with random total_paid_amounts. We just need to create a list of them.

context 'with cashouts' do
  let(:cashouts) {
    create_list(:cashout, 3)
  }

  describe '.sort_by_total_paid_amount_asc' do
    it 'sorts by total_paid_amount in ascending order' do
      expect(
        Cashout.sort_by_total_paid_amount_asc.to_a
      ).to eq cashouts.sort_by(&:total_amount_paid)
    end
  end

  describe '.sort_by_total_paid_amount_desc' do
    it 'sorts by total_paid_amount in descending order' do
      expect(
        Cashout.sort_by_total_paid_amount_desc.to_a
      ).to eq cashouts.sort_by(&:total_amount_paid).reverse
    end
  end
end

I avoided generating the cashouts in order. This would put them in the table already in order and their default sorting might match our expectations.

Though I question the value of such literally named and trivial scopes. They're easily written as Cashout.order(total_paid_amount: :asc) which requires no testing.

Testing add_virtual_columns... add_virtual_columns is a poor name. It seems like it's adding a single column, unpaid_amount. I'd call it with_unpaid_amount.

with_unpaid_amount is more complicated because it's pretty complicated and requires more test data. Fortunately we have our relationships set up in our factories.

First, we set up our objects so they all share the same partner. There's several ways to do this, but I've chosen to generate the partner and pass it around. This makes it easier to modify each object to test different scenarios.

describe '.with_unpaid_amount' do
  let(:partner) {
    create(:partner)
  }
  let(:company) {
    create(:company, partner: partner)
  }
  let(:cashout) {
    create(:cashout, partner: partner)
  }
  let(:contact_record) {
    create(:contact_record, partner: partner)
  }

With this in place you can now alter the objects to test different scenarios. For example, what if a partner is an administrator?

  context 'when the partner is an administrator' do
    before {
      partner.update!(partner_type: 'administrator')
    }

    it '...'
  end

And so on from there.


问:
Loop nested arrays with pixel data to one array

In here example we have arrays matrix 2*2 but it could be any e.g. 4x4, 16x16.

e.g.: we go through first array line 1 and then we go through second array line 1. After we come to the end of array's 2 last items we jump to the third array and so on. We know that every array (image parts) contains 64 columns/rows (pixels), so for 128px image we loop 2 arrays through and then move bottom ones.

What is the formula for looping through arrays in this kind of scenarios?

Here is something that I trying to do, but not work...

```<code># e.g. we have final image 128x128, so we have parts 4 * 64x64

# Empty arrays for every pixel
final_image_pixels = [None] * part_pixel_count * total_parts_count

# Loop through every parts
for i in range(len(image_pixels)):
    for x in range(part_width):
        for y in range(part_height):
            # Get location on part
            px_part_index = x + y * part_width
            # Index on final array
            px_final_index = px_part_index + (i * part_pixel_count)
            final_image_pixels[px_final_index] = image_pixels[i][px_part_index]
</code>```

Result Now:
(These colors do not relate to description image above)

Should be:

答:
Finally, I managed to combine image parts together with looping nested arrays. Although the script itself is not the most beautiful... I mark this answer to correct now, but if somebody is doing better that works in this context, I'll change it.

So here is "monster" that I've used in this case:

```<code>final_image_pixels = []
for i in range(parts_count, 0, -1):
    for row in range(part_height):
        part_switch = -1
        px_counter = -1
        for col in range(final_image_width):
            if col % part_width == 0:
                part_switch += 1
                px_counter = 0
            if i-1 == 0:
                px_arr = i-1 + part_switch
            else:
                px_arr = ((i-1) * parts_count) + part_switch
            target_pixel = row * part_width + px_counter
            final_image_pixels.append(part_pixels[px_arr][target_pixel])
            px_counter += 1
</code>```

Result:

If you want to investigate more about where I use this loop check here. This is part of RenderFart blender addon.

Body:
In here example we have arrays matrix 2*2 but it could be any e.g. 4x4, 16x16.

e.g.: we go through first array line 1 and then we go through second array line 1. After we come to the end of array's 2 last items we jump to the third array and so on. We know that every array (image parts) contains 64 columns/rows (pixels), so for 128px image we loop 2 arrays through and then move bottom ones.

What is the formula for looping through arrays in this kind of scenarios?

Here is something that I trying to do, but not work...

# e.g. we have final image 128x128, so we have parts 4 * 64x64

# Empty arrays for every pixel
final_image_pixels = [None] * part_pixel_count * total_parts_count

# Loop through every parts
for i in range(len(image_pixels)):
    for x in range(part_width):
        for y in range(part_height):
            # Get location on part
            px_part_index = x + y * part_width
            # Index on final array
            px_final_index = px_part_index + (i * part_pixel_count)
            final_image_pixels[px_final_index] = image_pixels[i][px_part_index]

Result Now:
(These colors do not relate to description image above)

Should be:

Body:
Finally, I managed to combine image parts together with looping nested arrays. Although the script itself is not the most beautiful... I mark this answer to correct now, but if somebody is doing better that works in this context, I'll change it.

So here is "monster" that I've used in this case:

final_image_pixels = []
for i in range(parts_count, 0, -1):
    for row in range(part_height):
        part_switch = -1
        px_counter = -1
        for col in range(final_image_width):
            if col % part_width == 0:
                part_switch += 1
                px_counter = 0
            if i-1 == 0:
                px_arr = i-1 + part_switch
            else:
                px_arr = ((i-1) * parts_count) + part_switch
            target_pixel = row * part_width + px_counter
            final_image_pixels.append(part_pixels[px_arr][target_pixel])
            px_counter += 1

Result:

If you want to investigate more about where I use this loop check here. This is part of RenderFart blender addon.


问:
Algorithm - Weighted interval scheduling problem variant
So I have a problem that goes as follows:

Xzqthpl is an alien living on the inconspicuous Kepler-1229b planet, a
  mere 870 or so light years away from Earth. Whether to see C-beams
  outside Tannhäuser Gate or just visiting Sirius for a good suntan,
  Xzqthpl enjoys going on weekend trips to different faraway stars and
  galaxies. However, because the universe is expanding, some of those
  faraway places are going to move further and further away from
  Kepler-1129b as time progresses. As a result, at some point in the
  distant future even relatively nearby galaxies like Andromeda will be
  too far away from Kepler-1229b for Xzqthpl to be able to do a weekend
  trip there because the journey back and forth would take too much
  time. There is a list of "n" places of interest to potentially visit.
  For each place, Xzqthpl has assigned a value "v_i" measuring how
  interested Xzqthpl is in the place, and a value "t_i" indicating the
  number of weeks from now after which the place will be too far away to
  visit.

Now Xzqthpl would like to plan its weekend trips in the following way:

No place is visited more than once.

At most one place is visited each week.

Place "i" is not visited after week "t_i"

The sum of values "v_i" for the visited places is maximized

Design an efficient (polynomial in "n" and independent of the v_i’s
  and t_i’s assuming the unit cost model) algorithm to solve Xzqthpl’s
  travel planning problem.

Currently I don't really know where to start. This feels like a weird variant of the "Weighted Interval Scheduling" algorithm (though I am not sure). Could someone give me some hints on where to start?

My inital thought is to sort the list by "t_i" in ascending order... but I am not really sure of what to do past that point (and my idea might even be wrong).

Thanks!

答:
You could use a min-heap for this:

Algorithm

Sort the input by ti

Create an empty min-heap, which will contain the vi that are retained

Iterate the sorted input. For each i:

If ti < size of heap, then this means this element cannot be retained, unless another, previously selected element is kicked out. Check if the minimum value in the heap is less that vi. If so, then it is beneficial to take that minimum value out of the heap, and put this vi instead.

Otherwise, just add vi to the heap.

In either case, keep the total value of the heap updated

Return the total value of the heap

Why this works

This works, because at each iteration we have this invariant:

The size of the heap represents two things at the same time. It is both:

The number of items we still consider as possible candidates for the final solution, and

The number of weeks that have passed.

The idea is that every item in the heap is assigned to one week, and so we need just as many weeks as there are items in the heap.

So, in every iteration we try to progress with 1 week. However, if the next visited item could only be allowed in the period that has already passed (i.e. its last possible week is a week that is already passed), then we can't just add it like that to the heap, as there is no available week for it. Instead we check whether the considered item would be better exchanged with an item that we already selected (and is in the heap). If we exchange it, the one that loses out, cannot stay in the heap, because now we don't have an available week for that one (remember its time limit is even more strict -- we visit them in order of time limit). So whether we exchange or not, the heap size remains the same.

Secondly, the heap has to be a heap, because we want an efficient way to always know which is the element with the least value. Otherwise, if it were a simple list, we would have to scan that list in each iteration, in order to compare its value with the one we are currently dealing with (and want to potentially exchange). Obviously, an exchange is only profitable, if the total value of the heap increases. So we need an efficient way to find a bad value fast. A min-heap provides this.

An Implementation

Here is an implementation in Python:

from collections import namedtuple
from heapq import heappush, heapreplace

Node = namedtuple("Node", "time,value")

def kepler(times, values):
    n = len(values)
    # Combine corresponding times and values
    nodes = [Node(times[i], values[i]) for i in range(n)];
    nodes.sort() # by time

    totalValue = 0
    minheap = []
    for node in nodes:
        if node.time < len(minheap): # Cannot be visited in time
            leastValue = minheap[0] # See if we should replace
            if leastValue < node.value:
                heapreplace(minheap, node.value) # pop and insert
                totalValue += node.value - leastValue
        else:
            totalValue += node.value
            heappush(minheap, node.value)
    return totalValue
```

<p>And here is some sample input for it:</p>

<pre class="lang-py prettyprint-override"><code>times = [3,3,0,2,6,2,2]
values =[7,6,3,2,1,4,5]

value = kepler(times, values)
print(value) # 23
</code>```

Time Complexity

Sorting would represent O(nlogn) time complexity. Even though one could consider some radix sort to get that down to O(n), the use of the heap also represents a worst case of O(nlogn). So the algorithm has a time complexity of O(nlogn).

Body:
You could use a min-heap for this:

Algorithm

Sort the input by ti

Create an empty min-heap, which will contain the vi that are retained

Iterate the sorted input. For each i:

If ti < size of heap, then this means this element cannot be retained, unless another, previously selected element is kicked out. Check if the minimum value in the heap is less that vi. If so, then it is beneficial to take that minimum value out of the heap, and put this vi instead.

Otherwise, just add vi to the heap.

In either case, keep the total value of the heap updated

Return the total value of the heap

Why this works

This works, because at each iteration we have this invariant:

The size of the heap represents two things at the same time. It is both:

The number of items we still consider as possible candidates for the final solution, and

The number of weeks that have passed.

The idea is that every item in the heap is assigned to one week, and so we need just as many weeks as there are items in the heap.

So, in every iteration we try to progress with 1 week. However, if the next visited item could only be allowed in the period that has already passed (i.e. its last possible week is a week that is already passed), then we can't just add it like that to the heap, as there is no available week for it. Instead we check whether the considered item would be better exchanged with an item that we already selected (and is in the heap). If we exchange it, the one that loses out, cannot stay in the heap, because now we don't have an available week for that one (remember its time limit is even more strict -- we visit them in order of time limit). So whether we exchange or not, the heap size remains the same.

Secondly, the heap has to be a heap, because we want an efficient way to always know which is the element with the least value. Otherwise, if it were a simple list, we would have to scan that list in each iteration, in order to compare its value with the one we are currently dealing with (and want to potentially exchange). Obviously, an exchange is only profitable, if the total value of the heap increases. So we need an efficient way to find a bad value fast. A min-heap provides this.

An Implementation

Here is an implementation in Python:

from collections import namedtuple
from heapq import heappush, heapreplace

Node = namedtuple("Node", "time,value")

def kepler(times, values):
    n = len(values)
    # Combine corresponding times and values
    nodes = [Node(times[i], values[i]) for i in range(n)];
    nodes.sort() # by time

    totalValue = 0
    minheap = []
    for node in nodes:
        if node.time < len(minheap): # Cannot be visited in time
            leastValue = minheap[0] # See if we should replace
            if leastValue < node.value:
                heapreplace(minheap, node.value) # pop and insert
                totalValue += node.value - leastValue
        else:
            totalValue += node.value
            heappush(minheap, node.value)
    return totalValue

And here is some sample input for it:

times = [3,3,0,2,6,2,2]
values =[7,6,3,2,1,4,5]

value = kepler(times, values)
print(value) # 23

Time Complexity

Sorting would represent O(nlogn) time complexity. Even though one could consider some radix sort to get that down to O(n), the use of the heap also represents a worst case of O(nlogn). So the algorithm has a time complexity of O(nlogn).


问:
Changing state in onAppear breaks PageViewController
I'm struggling to understand why a PageViewController does not work as expected when there is a change to a @Published EnvironmentObject variable during .onAppear in its parent View.

If I comment out the .onAppear modifier in DetailView, then everything works fine - the slides swipe as expected of a PageViewController. But as soon as that modifier is back in, then the pages do not swipe correctly.

It's got to be something to do with the re-render due to state change, but I can't figure it out. I know that updateUIViewController is called on the state change, and this seems to change the array of viewControllers.

If anyone has a steer on how to solve this, I'll be really grateful to hear about it!

If you are running the code below, make sure to change your SceneDelegate:

```<code>let contentView = ContentView()
</code>```

to

```<code>let contentView = ContentView().environmentObject(Global())
</code>```

So here's a simple example of the issue:

import SwiftUI
import Foundation
import UIKit

struct Item: Hashable {
  var text: String
}

let testItems: [Item] = [
  Item(text: "I am item 1"),
  Item(text: "I am item 2"),
  Item(text: "I am item 3")
]

final class Global : ObservableObject {
  @Published var hideText: Bool = false
}

struct ContentView: View {

  @EnvironmentObject var global: Global

  var body: some View {

    NavigationView {
      VStack {
        List(testItems, id: \.self) { item in
          NavigationLink(destination: DetailView(item: item)) {
            Text(item.text)
          }
        }

        Text("I should vanish when detail view loads")
          .opacity(self.global.hideText ? 0 : 1)
      }
      .navigationBarTitle("Test")
    }
  }
}

struct DetailView: View {

  @EnvironmentObject var global: Global

  var item: Item
  var testViews: [Text] = [
    Text("Slide 1").font(.title),
    Text("Slide 2").font(.title),
    Text("Slide 3").font(.title),
  ]

  var body: some View {

    // The .onAppear modifier breaks the PageViewController
    // when it is commented out, the slides work as expected

    PageView(testViews)
      .onAppear {
        self.global.hideText = true
      }
  }
}

struct PageView<Page: View>: View {

  @State var currentPage = 0

  var viewControllers: [UIHostingController<Page>]

  init(_ views: [Page]) {
    self.viewControllers = views.map{ UIHostingController(rootView: $0) }
  }

  var body: some View {
    VStack(alignment: .center) {
      PageViewController(
        viewControllers: viewControllers,
        currentPageIndex: $currentPage
      )
    }
  }
}

struct PageViewController: UIViewControllerRepresentable {

  var viewControllers: [UIViewController]

  @Binding var currentPageIndex: Int

  func makeCoordinator() -> Coordinator {
    Coordinator(self)
  }

  func makeUIViewController(context: Context) -> UIPageViewController {
    let pageViewController = UIPageViewController(
      transitionStyle: .scroll,
      navigationOrientation: .horizontal
    )

    pageViewController.view.backgroundColor = UIColor.clear
    pageViewController.dataSource = context.coordinator
    pageViewController.delegate = context.coordinator

    return pageViewController
  }

  func updateUIViewController(_ pageViewController: UIPageViewController, context: Context) {
    pageViewController.setViewControllers([viewControllers[currentPageIndex]], direction: .forward, animated: true)
  }

  class Coordinator: NSObject, UIPageViewControllerDataSource, UIPageViewControllerDelegate {

    var parent: PageViewController

    init(_ pageViewController: PageViewController) {
      self.parent = pageViewController
    }

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        // retrieves the index of the currently displayed view controller
        guard let index = parent.viewControllers.firstIndex(of: viewController) else {
          return nil
        }

        // shows the last view controller when the user swipes back from the first view controller
        if index == 0 {
          return parent.viewControllers.last
        }

        //show the view controller before the currently displayed view controller
        return parent.viewControllers[index - 1]
      }

      func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
          // retrieves the index of the currently displayed view controller
          guard let index = parent.viewControllers.firstIndex(of: viewController) else {
            print("View controller not found!!")
            return nil
          }
          // shows the first view controller when the user swipes further from the last view controller
          if index + 1 == parent.viewControllers.count {
            return parent.viewControllers.first
          }

          // show the view controller after the currently displayed view controller
          return parent.viewControllers[index + 1]
      }

      func pageViewController(_ pageViewController: UIPageViewController,
        didFinishAnimating finished: Bool,
        previousViewControllers: [UIViewController],
        transitionCompleted completed: Bool
      ) {
        if completed,
          let visibleViewController = pageViewController.viewControllers?.first,
          let index = parent.viewControllers.firstIndex(of: visibleViewController) {
            parent.currentPageIndex = index
          }
      }
  }
}

struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    ContentView()
      .environmentObject(Global())
  }
}
```

答:
This builds on a helpful answer by @Mac3n, who correctly pointed out that making the ViewControllers passed to the UIViewControllerRepresentable part of state fixes the issue. All that was missing was how to actually do that via the init method.

Here is the full update to PageView

```<code>struct PageView<Page: View>: View {

  @State var currentPage = 0
  @State var viewControllers: [UIHostingController<Page>]

  init(_ views: [Page]) {
    _viewControllers = State(initialValue: views.map{ UIHostingController(rootView: $0) })
  }

  var body: some View {
    VStack(alignment: .center) {
      PageViewController(
        viewControllers: viewControllers,
        currentPageIndex: $currentPage
      )
    }
  }
}
</code>```

Body:
I'm struggling to understand why a PageViewController does not work as expected when there is a change to a @Published EnvironmentObject variable during .onAppear in its parent View.

If I comment out the .onAppear modifier in DetailView, then everything works fine - the slides swipe as expected of a PageViewController. But as soon as that modifier is back in, then the pages do not swipe correctly.

It's got to be something to do with the re-render due to state change, but I can't figure it out. I know that updateUIViewController is called on the state change, and this seems to change the array of viewControllers.

If anyone has a steer on how to solve this, I'll be really grateful to hear about it!

If you are running the code below, make sure to change your SceneDelegate:

let contentView = ContentView()

to

let contentView = ContentView().environmentObject(Global())

So here's a simple example of the issue:

import SwiftUI
import Foundation
import UIKit

struct Item: Hashable {
  var text: String
}

let testItems: [Item] = [
  Item(text: "I am item 1"),
  Item(text: "I am item 2"),
  Item(text: "I am item 3")
]

final class Global : ObservableObject {
  @Published var hideText: Bool = false
}

struct ContentView: View {

  @EnvironmentObject var global: Global

  var body: some View {

    NavigationView {
      VStack {
        List(testItems, id: \.self) { item in
          NavigationLink(destination: DetailView(item: item)) {
            Text(item.text)
          }
        }

        Text("I should vanish when detail view loads")
          .opacity(self.global.hideText ? 0 : 1)
      }
      .navigationBarTitle("Test")
    }
  }
}

struct DetailView: View {

  @EnvironmentObject var global: Global

  var item: Item
  var testViews: [Text] = [
    Text("Slide 1").font(.title),
    Text("Slide 2").font(.title),
    Text("Slide 3").font(.title),
  ]

  var body: some View {

    // The .onAppear modifier breaks the PageViewController
    // when it is commented out, the slides work as expected

    PageView(testViews)
      .onAppear {
        self.global.hideText = true
      }
  }
}

struct PageView<Page: View>: View {

  @State var currentPage = 0

  var viewControllers: [UIHostingController<Page>]

  init(_ views: [Page]) {
    self.viewControllers = views.map{ UIHostingController(rootView: $0) }
  }

  var body: some View {
    VStack(alignment: .center) {
      PageViewController(
        viewControllers: viewControllers,
        currentPageIndex: $currentPage
      )
    }
  }
}

struct PageViewController: UIViewControllerRepresentable {

  var viewControllers: [UIViewController]

  @Binding var currentPageIndex: Int

  func makeCoordinator() -> Coordinator {
    Coordinator(self)
  }

  func makeUIViewController(context: Context) -> UIPageViewController {
    let pageViewController = UIPageViewController(
      transitionStyle: .scroll,
      navigationOrientation: .horizontal
    )

    pageViewController.view.backgroundColor = UIColor.clear
    pageViewController.dataSource = context.coordinator
    pageViewController.delegate = context.coordinator

    return pageViewController
  }

  func updateUIViewController(_ pageViewController: UIPageViewController, context: Context) {
    pageViewController.setViewControllers([viewControllers[currentPageIndex]], direction: .forward, animated: true)
  }

  class Coordinator: NSObject, UIPageViewControllerDataSource, UIPageViewControllerDelegate {

    var parent: PageViewController

    init(_ pageViewController: PageViewController) {
      self.parent = pageViewController
    }

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        // retrieves the index of the currently displayed view controller
        guard let index = parent.viewControllers.firstIndex(of: viewController) else {
          return nil
        }

        // shows the last view controller when the user swipes back from the first view controller
        if index == 0 {
          return parent.viewControllers.last
        }

        //show the view controller before the currently displayed view controller
        return parent.viewControllers[index - 1]
      }

      func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
          // retrieves the index of the currently displayed view controller
          guard let index = parent.viewControllers.firstIndex(of: viewController) else {
            print("View controller not found!!")
            return nil
          }
          // shows the first view controller when the user swipes further from the last view controller
          if index + 1 == parent.viewControllers.count {
            return parent.viewControllers.first
          }

          // show the view controller after the currently displayed view controller
          return parent.viewControllers[index + 1]
      }

      func pageViewController(_ pageViewController: UIPageViewController,
        didFinishAnimating finished: Bool,
        previousViewControllers: [UIViewController],
        transitionCompleted completed: Bool
      ) {
        if completed,
          let visibleViewController = pageViewController.viewControllers?.first,
          let index = parent.viewControllers.firstIndex(of: visibleViewController) {
            parent.currentPageIndex = index
          }
      }
  }
}

struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    ContentView()
      .environmentObject(Global())
  }
}

Body:
This builds on a helpful answer by @Mac3n, who correctly pointed out that making the ViewControllers passed to the UIViewControllerRepresentable part of state fixes the issue. All that was missing was how to actually do that via the init method.

Here is the full update to PageView

struct PageView<Page: View>: View {

  @State var currentPage = 0
  @State var viewControllers: [UIHostingController<Page>]

  init(_ views: [Page]) {
    _viewControllers = State(initialValue: views.map{ UIHostingController(rootView: $0) })
  }

  var body: some View {
    VStack(alignment: .center) {
      PageViewController(
        viewControllers: viewControllers,
        currentPageIndex: $currentPage
      )
    }
  }
}