データストラクチャー Arrays
Data Structure Array
Static arrayとDynamic arrayがある。Jsなどのhigh level languageでは特に意識することないが、low level languageなどでは気にする必要がある。
JavaでいうArrayはstatic / ArrayListはdynamicにあたる。
ArraysのBigO
| Static | Dynamic | Big O |
|---|---|---|
| lookup | lookup | O(1) |
| push | append | O(1) |
| insert | insert | O(n) |
| delete | delete | O(n) |
※appendはO(n)になり得る。
Ex)
const string = ['a', 'b', 'c', 'd', 'e']; // 4 * 4 の16bytesのstorage strings.push('e'); // O(1) strings.push(); // O(1) strings.unshift('x'); // O(n) strings.splice(2, 0, 'e'); // O(n)
unshiftとspliceがO(n)になる理由は、値が配列の先頭または指定箇所に代入されることによって、 それまでのindexの位置がループによって書き換えられるため。
class MyArray{ constructor() { this.length = 0; this.data = {}; } get(index) { return this.data[index]; } push(item) { this.data[this.length] = item; this.length++; return this.length; } pop(){ const lastItem = this.data[this.length -1]; delete this.data[this.length-1]; this.length--; return lastItem; } delete(index) { const item = this.data[index]; this.shuftItems(index); return item; } shuftItems(index) { for(let i = index; i < this.length -1; i++){ this.data[i] = this.data[i+1]; } delete this.data[this.length-1]; this.length--; } } const newArray = new MyArray(); newArray.push('hi'); newArray.push('world'); newArray.pop(); console.log(newArray);
Ex1) Reverse String
const reverseString = (string) => { let arr = string.split(""); let reverseArr = []; for(let i = 0; i < arr.length; i++){ reverseArr.unshift(arr[i]); } console.log(reverseArr.join('')) } reverseString("apple is good"); const reverseString2 = (string) => { // check input if(!string || string.length < 2 || typeof string !== 'string') { return "that is not good"; } const backwords = []; const totalItems = string.length - 1; for(let i = totalItems; i >= 0; i--){ backwords.push(string[i]); } return backwords.join(''); } const reverseString3 = (str) => { return str.split('').reverse().join(); } const reverseString4 = (str) => str.split('').reverse().join(); const reverseString5 = str => [...str].reverse().join(); console.log(reverseString2("banana is soso"));
Data Structureの問題を解く際に、inputのチェックをすることが大事。
EX2) MergeSortedArray
mergeSortedArrays([0,3,4,31], [4,6,30]); const mergeSortedArrays = (arr1, arr2) => { const arr = arr1.concat(arr2); arr.sort((a, b) => a-b); console.log(arr.join(',')); } const mergeSortedArrays1 = (arr1, arr2) => { const mergedArray = []; let array1Item = arr1[0]; let array2Item = arr2[0]; let i = 1; let j = 1; // check input if(arr1.length === 0) { return arr2; } if(arr2.length === 0){ return arr1; } while(array1Item || array2Item) { if(!array2Item || array1Item < array2Item) { mergedArray.push(array1Item); array1Item = arr1[i]; i++; } else { mergedArray.push(array2Item); array2Item = arr2[j]; j++; } } return mergedArray; } console.log(mergeSortedArrays1([0,3,4,31], [4,6,30]));
ArraysのProsとCons
| Pros | Cons |
|---|---|
| Fast lookups | Slow Inserts |
| Fast push/pop | Slow deletes |
| Ordered | Fixed size* |
*static Arrayを使う場合
React-Reduxアプリケーション開発入門まとめ
概要
こんにちはtogashoです。
今回はフロントエンドエンジニアのためのReact・Reduxアプリケーション開発入門の基礎編で学んだReactとReduxの基本的なところを自分の忘備録も兼ねてをまとめてみました。
React
Facebook社が開発したライブラリー
- DOMの変更箇所だけをレンダリングする
- DOMの変更箇所がどこかを開発者が気にする必要がない
JSX
javascript XMLの略。
JSXの利点とは
jsでも表示できるが、JSXの方が直感的にコーディングでき可読性が高い。
文法
- JSXが使われているときは
reactをimportする必要がある。JSXを使わなければreactは必要ない。 {}の中では、jsが実行できる。- classはclassNameと定義する。
- 属性名はキャメルケースで定義する。
onClickやonChangeなど - returnで複数の要素を返す場合、divタグで囲む。
Fragmentはdivタグで囲むのと同じ役割をするが、ブラウザ上では表示されない。
トランスパイル
JSXを実行可能なjsに変換すること。Babelが暗黙的にやっている。
Webpack
モジュールバンドラー。ソースコードを束ねて、一つのファイルにまとめて定義し、ブラウザで表示する。
コンポーネント
関数の定義によるものとクラス定義によるものがある。
// 関数定義
import React from 'react'
const Register = () => {
return (
<div>
</div>
)
}
export default Register
//クラス定義
import React, { Component } from 'react'
export default class Register extends Component {
render() {
return (
<div>
</div>
)
}
}
props
- コンポーネントの属性の名前。{}で囲って値を渡す。親から子にデータを渡す。
- immutable(変更不可能)な値
//ex)
import React from 'react'
const App = () => {
const profiles = [
{name: "Taro", age: 18},
{name: "Sam", age: 21},
{name: "Bob"},
]
return (
<div>
{
// コンポーネントにpropsを渡す
profiles.map((profile, index) => {
return <User name={profile.name} age={profile.age} key={index} />
})
}
</div>
)
}
// 親から渡されたpropsを引数として受け取る。
const User = (props) => {
return (
<div>Hi, I am {props.name}, and {props.age} years old!</div>
)
}
// デフォルトのpropsの設定
User.defaultProps = {
age: 1
}
export default App
prop-types
- propertiesに対する型のチェックをするためのパッケージ。
import Proptypes from 'prop-types'でimportするisRequiredで必須にできる。- コンポーネントを設計する段階で、受け取るプロパティの型がぶれないように設計することが大事
//ex)
User.propTypes = {
name: Proptypes.strng,
age: Proptypes.number
}
State
- コンポーネントの中で状態を保つこと。コンポーネント内部でしか使えない
- mutable(変更可能)な値
this.stateでアクセスできるthis.setStateで状態を変える。setStateが実行されるとそのコールバックでrenderが再実行される
import React, { Component, Fragment } from 'react';
const App = () => (<Counter></Counter>);
class Counter extends Component {
// constructorはcomponentの初期化時に呼ばれるコールバック
constructor(props){
super(props)
this.state = { count: 0}
}
handlePlusButton(){
this.setState({count: this.state.count +1 })
}
handleMinusButton(){
this.setState({count: this.state.count - 1 })
}
render() {
return (
<Fragment>
<div>count: {this.state.count}</div>
<button onClick={this.handlePlusButton}>+1</button>
<button onClick={this.handleMinusButton}>-1</button>
</Fragment>
)
}
}
export default App;
Reduxの概要
コンポーネントの階層が大きくなった時に、容易に状態を共有する手段を提供する。
action
- アプリケーションの中で何が起きたかを示すデータ。jsオブジェクトのこと。
- typeというキー(ユニークでなけれならない)とタイプに対応する値を持つ。
action creator
- actionを定義して、それを返す関数のことをaction creatorと呼ぶ
- typeで指定した値は、reducerでも使う。
- viewを担当するコンポーネントがactionをimportして、あるイベントを掴んだ時に当該のaction creatorをinvokeして適切な状態遷移を実行させるための仕組み。
export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';
// action creator
export const increment = () => ({
type: INCREMENT
})
export const decrement = () => ({
type: DECREMENT
})
Reducer
- actionが発生した時に、そのアクションに組み込まれているtypeに応じて状態をどのように変化させるのかを定義するもの
- 状態は、コードの中ではstateという名称で扱う。
- アプリケーションの事実上の状態を持つreducerを定義する。
// index.js
// アプリケーション内に存在する全てのreducerを総括する。全てのreducerを結合する。
//combineReducersがreducerを結合する
import { combineReducers} from 'redux';
import count from './count';
export default combineReducers({ count });
// counter.js
// actionをimportする
import { INCREMENT, DECREMENT} from '../actions/index';
//状態をの初期値を定義する
const initialState = { value: 0 }
// actionのtypeを受け取り、switch文で状態をどう変化させるのかを定義する。
export default (state = initialState, action) => {
switch (action.type){
case INCREMENT:
return { value: state.value + 1}
case DECREMENT:
return { value: state.value - 1}
default:
return state
}
}
Store
- reducerをもとにstoreを作成する。そのstoreが全てのアプリケーション内で使えるようにする。
createStore()で行う。 - storeを全コンポーネントを参照できるようにするため、
Providerがreact-reduxから提供されている。
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import App from './components/App';
import './index.css';
import reducer from './reducers';
// アプリケーション内の全てのstateはこのstateに集約されている
const store = createStore(reducer)
// 既存のcomponentをProviderでラッピングする
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
connectでstateとactionsとの関連づけ
- react-reduxが提供するconnect関数を使用して、stateやactionをコンポーネントに紐づける。viewのイベントで状態を遷移させ、遷移後の状態を再renderingする。
mapStateToPropsはstateの情報からこのコンポーネントで必要な物を取り出して、コンポーネント内のpropsとしてmappingする機能を持つ関数。引数には状態のtopレベルを表すstateを渡して、どういったオブジェクトをpropsに対応させるのかを関数の戻り値として定義する。mapDispatchToPropsあるアクションが発生した時にreducerにtypeに応じた状態遷移を実行させる関数がdispatch。dispatch関数を引数において、このコンポーネントに必要となるdispatch関数を宣言する。
import React, { Component, Fragment } from 'react';
import { connect } from 'react-redux';
// action creatorを呼び出す。
import { increment, decrement } from '../actions';
class App extends Component {
render() {
const props = this.props;
return (
<Fragment>
<div>value: { props.value }</div>
<button onClick={props.increment}>+1</button>
<button onClick={props.decrement}>-1</button>
</Fragment>
)
}
}
// stateとcomponentを関連づける
const mapStateToProps = state => ({value: state.count.value});
const mapDispatchToProps = ({increment, decrement});
// 下記でも可
// const mapDispatchToProps = dispatch => ({
// increment: () => dispatch(increment()),
// decrement: () => dispatch(decrement())
//})
// connectの引数にmapStateToPropsとmapDispatchToProps渡してAppに紐付ける。
export default connect(mapStateToProps, mapDispatchToProps)(App);
ご一読いただきありがとうございました。指摘事項等ございましたら、ご指摘いただけると幸いです。
天気予報アプリ(express無し)の実装
はじめに
はじめたのブログ投稿になります。現在、海外でwebエンジニアになるべくカナダのバンクーバのカレッジに通っています。勉強した内容や、カナダでの生活を記事にしていこうと思いますので、どうぞよろしくお願いいたします。
概略
この記事ではUdemyのThe Complete Node.js Developer Course(3rd Edition)のSection6~9の内容を簡単にまとめました。
ここでは、APIを取得する方法とjsonで渡された値の取得方法を学びました。
Topic
- Callback関数
- Fetch
- json
- コマンド引数
- module(import/export)
- 分割代入
使用ライブラリ
- request (簡単にhttpを作成するためのライブラリ)
使用API
実装
// app.js
// utilsをimport(nodejsはimportではなく、requireでモジュールを取得する)
const geocode = require('./utils/geocode');
const forecast = require('./utils/forecast');
// コマンドから渡された引数を格納する
const addres = process.argv[2];
// 引数が渡されなかったら、エラーを返す。
if(!address) {
return console.log('please provide an address')
}
// geocodeを実行し、エラーがない場合、latitude,longitude,loactionを取得し、forecastに値を渡す。
geocode(address, (error, {latitude, longitude, location})=> {
if(error){
return console.log(error);
}
// geocodeから渡された、latitudeとlongitudeをもとに天気予報と降水確率を返す。
forecast(latitude, longitude, (error, forecastData)=>{
if(error) {
return console.log(error);
}
console.log(location);
console.log(forecastData);
})
})
// geocode.js
const request = require('request')
// importしたgeocode()を呼び出す。addressにはコマンド引数が渡される。
const geocode = (address, callback) => {
//mapboxをfetchする。
const url = 'https://api.mapbox.com/geocoding/v5/mapbox.places/'+ encodeURIComponent(address) + '.json?access_token=pk.eyJ1IjoidGd3IiwiYSI6ImNqdXBsN3ZlOTNiM3k0M252MzA1ZzY2NTkifQ.ucwg_oXHd7KDVTHgSufvTQ';
// urlが正しく、json型で返されているかを判定する。
request({url: url, json: true}, (error,{body})=>{
// Urlが不正な場合、errorを返す
if(error){
callback('Unable to connect location service', undefined);
// body.featuresに値がない場合、エラーを返す
} else if(body.features.length === 0) {
callback('unable to find your location', undefined);
// 正常に値が返ってきた場合、latitude, longitude, locationを返す
} else {
callback(undifined, {
latitude: body.features[0].center[1];
longitude: body.feature[0].center[0],
location: body.features[0].place_name
})
}
})
}
// forecast.js
const request = require('request')
const forecast = (latitude, longitude, callback) => {
const url = `https://api.darksky.net/forecast/cc390e4b8d3d1951f092c99243ae915d/${latitude},${longitude}?units=si`;
//渡されたurlが正しく、json型で返ってきた場合、天気予報と降水確率を返す。
request({url, json: true},(error, { body })=>{
if(error) {
callback('unable to connect service', undefined);)
} else if (body.error) {
callback('unable to find location', undefined)
} else {
callback(undefined, `${body.daily.summary}, ${body.daily.data[0].precipProbablity}%`)
}
})
}
module.exports = forecast;
mapbox api (ここではcenterの緯度経緯度を取得)
features: [
{
id: "place.9391334652012190",
type: "Feature",
place_type: [
"place"
],
relevance: 1,
properties: {
wikidata: "Q100"
},
text: "Boston",
place_name: "Boston, Massachusetts, United States",
bbox: [
-71.1255750165112,
42.3196059806256,
-70.9860500028801,
42.3974009328397
],
center: [
-71.0596,
42.3605
],
geometry: {
type: "Point",
coordinates: [
-71.0596,
42.3605
]
},
context: [
{
id: "region.6776276020561540",
short_code: "US-MA",
wikidata: "Q771",
text: "Massachusetts"
},
{
id: "country.9053006287256050",
short_code: "us",
wikidata: "Q30",
text: "United States"
}
]
},
darksky api (mapboxから取得した緯度経度をもとにdaily.sammaryとdaily.data[0]. precipProbabilityを取得)
実際、日々の生活でみるデータのやり取りが、このようなフォーマットで行われています。瞬時にデータのやり取りをするコンピュータはすごいですね!
{
latitude: 42.3605,
longitude: -71.0596,
timezone: "America/New_York",
currently: {
time: 1556073863,
summary: "Overcast",
icon: "cloudy",
nearestStormDistance: 0,
precipIntensity: 0,
precipProbability: 0,
temperature: 7.82,
apparentTemperature: 6.93,
dewPoint: 6.27,
humidity: 0.9,
pressure: 1011.35,
windSpeed: 1.72,
windGust: 2.83,
windBearing: 122,
cloudCover: 1,
uvIndex: 0,
visibility: 15.59,
ozone: 331.58
},
daily: {
summary: "Light rain today through Saturday, with high temperatures rising to 20°C on Sunday.",
icon: "rain",
data: [
{
time: 1555992000,
summary: "Overcast throughout the day.",
icon: "cloudy",
sunriseTime: 1556013117,
sunsetTime: 1556062523,
moonPhase: 0.65,
precipIntensity: 0.3277,
precipIntensityMax: 2.3292,
precipIntensityMaxTime: 1555995600,
precipProbability: 1,
precipType: "rain",
temperatureHigh: 12.1,
temperatureHighTime: 1556038800,
temperatureLow: 7.68,
temperatureLowTime: 1556071200,
apparentTemperatureHigh: 12.1,
apparentTemperatureHighTime: 1556038800,
apparentTemperatureLow: 6.71,
apparentTemperatureLowTime: 1556082000,
dewPoint: 7.77,
humidity: 0.88,
pressure: 1013.36,
windSpeed: 1.72,
windGust: 5.15,
windGustTime: 1556024400,
windBearing: 43,
cloudCover: 1,
uvIndex: 4,
uvIndexTime: 1556035200,
visibility: 11.04,
ozone: 332.64,
temperatureMin: 7.68,
temperatureMinTime: 1556071200,
temperatureMax: 12.1,
temperatureMaxTime: 1556038800,
apparentTemperatureMin: 6.86,
apparentTemperatureMinTime: 1556002800,
apparentTemperatureMax: 12.1,
apparentTemperatureMaxTime: 1556038800
}
終わりに
この記事では、講座の中で紹介されていたexpressを使用しない実装方法を紹介しました。この講座の中では、expressを使って同じapiを叩く実装も紹介されているので、後日紹介できればと思います。
ご指摘いただけることがありましたら、ご指摘いただけると幸いです。お読みいただきありがとうございました。